You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by er...@apache.org on 2003/06/27 09:16:58 UTC

cvs commit: xml-axis/java/src/org/apache/axis/types Day.java IDRefs.java Month.java MonthDay.java NMTokens.java Notation.java Time.java Year.java YearMonth.java

ericf       2003/06/27 00:16:58

  Modified:    java/src/org/apache/axis/types Day.java IDRefs.java
                        Month.java MonthDay.java NMTokens.java
                        Notation.java Time.java Year.java YearMonth.java
  Log:
  implemented hashCode() in classes that override equals() as required by
  the contract between those two methods (see java.lang.Object)
  Made equals() implementation in IDRefs and NMTokens insensitive to
  order, as those types represents sets, not lists.
  
  Revision  Changes    Path
  1.9       +23 -13    xml-axis/java/src/org/apache/axis/types/Day.java
  
  Index: Day.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/Day.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Day.java	5 May 2003 00:36:08 -0000	1.8
  +++ Day.java	27 Jun 2003 07:16:57 -0000	1.9
  @@ -60,10 +60,10 @@
   
   /**
    * Implementation of the XML Schema type gDay
  - * 
  + *
    * @author Tom Jordahl <to...@macromedia.com>
    * @see <a href="http://www.w3.org/TR/xmlschema-2/#gDay">XML Schema 3.2.13</a>
  - */ 
  + */
   public class Day implements java.io.Serializable {
       int day;
       String timezone = null;
  @@ -71,7 +71,7 @@
       /**
        * Constructs a Day with the given values
        * No timezone is specified
  -     */ 
  +     */
       public Day(int day) throws NumberFormatException {
           setValue(day);
       }
  @@ -79,28 +79,28 @@
       /**
        * Constructs a Day with the given values, including a timezone string
        * The timezone is validated but not used.
  -     */ 
  -    public Day(int day, String timezone) 
  +     */
  +    public Day(int day, String timezone)
           throws NumberFormatException {
           setValue(day, timezone);
       }
  -    
  +
       /**
        * Construct a Day from a String in the format ---DD[timezone]
  -     */ 
  +     */
       public Day(String source) throws NumberFormatException {
           if (source.length() < 5) {
               throw new NumberFormatException(
                       Messages.getMessage("badDay00"));
           }
  -        
  +
           if (source.charAt(0) != '-' ||
               source.charAt(1) != '-' ||
               source.charAt(2) != '-' ) {
               throw new NumberFormatException(
                       Messages.getMessage("badDay00"));
           }
  -        
  +
           setValue(Integer.parseInt(source.substring(3,5)),
                    source.substring(5));
       }
  @@ -111,7 +111,7 @@
   
       /**
        * Set the day
  -     */ 
  +     */
       public void setDay(int day) {
           // validate day
           if (day < 1 || day > 31) {
  @@ -148,12 +148,12 @@
           }
       }
   
  -    public void setValue(int day, String timezone) 
  +    public void setValue(int day, String timezone)
           throws NumberFormatException {
           setDay(day);
           setTimezone(timezone);
       }
  -    
  +
       public void setValue(int day) throws NumberFormatException {
           setDay(day);
       }
  @@ -179,11 +179,21 @@
           Day other = (Day) obj;
           if (obj == null) return false;
           if (this == obj) return true;
  -        
  +
           boolean equals = (this.day == other.day);
           if (timezone != null) {
               equals = equals && timezone.equals(other.timezone);
           }
           return equals;
  +    }
  +
  +    /**
  +     * Return the value of day XORed with the hashCode of timezone
  +     * iff one is defined.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        return null == timezone ? day : day ^ timezone.hashCode();
       }
   }
  
  
  
  1.5       +46 -7     xml-axis/java/src/org/apache/axis/types/IDRefs.java
  
  Index: IDRefs.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/IDRefs.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- IDRefs.java	22 Apr 2003 19:35:59 -0000	1.4
  +++ IDRefs.java	27 Jun 2003 07:16:57 -0000	1.5
  @@ -54,17 +54,20 @@
    */
   package org.apache.axis.types;
   
  +import java.util.Arrays;
  +import java.util.HashSet;
  +import java.util.Set;
   import java.util.StringTokenizer;
   
   /**
    * Custom class for supporting XSD data type IDRefs
  - * 
  + *
    * @author Davanum Srinivas <di...@yahoo.com>
    * @see <a href="http://www.w3.org/TR/xmlschema-2/#IDREFS">XML Schema 3.3.10 IDREFS</a>
    */
   public class IDRefs extends NCName {
       private IDRef[] idrefs;
  -    
  +
       public IDRefs() {
           super();
       }
  @@ -86,16 +89,52 @@
       }
   
       public String toString() {
  -        String val = "";
  +        StringBuffer buf = new StringBuffer();
           for (int i = 0; i < idrefs.length; i++) {
               IDRef ref = idrefs[i];
  -            if (i > 0) val += " ";
  -            val += ref.toString();
  +            if (i > 0) buf.append(" ");
  +            buf.append(ref.toString());
           }
  -        return val;
  +        return buf.toString();
       }
   
  +    /**
  +     * IDREFs can be equal without having identical ordering because
  +     * they represent a set of references.  Hence we have to compare
  +     * values here as a set, not a list.
  +     *
  +     * @param object an <code>Object</code> value
  +     * @return a <code>boolean</code> value
  +     */
       public boolean equals(Object object) {
  -        return (toString().equals(object.toString()));
  +        if (object == this) {
  +            return true;        // succeed quickly, when possible
  +        }
  +        if (object instanceof IDRefs) {
  +            IDRefs that = (IDRefs)object;
  +            if (this.idrefs.length == that.idrefs.length) {
  +                Set ourSet = new HashSet(Arrays.asList(this.idrefs));
  +                Set theirSet = new HashSet(Arrays.asList(that.idrefs));
  +                return ourSet.equals(theirSet);
  +            } else {
  +                return false;
  +            }
  +        } else {
  +            return false;
  +        }
  +    }
  +
  +    /**
  +     * Returns the sum of the hashcodes of the underlying idrefs, an
  +     * operation which is not sensitive to ordering.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        int hash = 0;
  +        for (int i = 0; i < idrefs.length; i++) {
  +            hash += idrefs[i].hashCode();
  +        }
  +        return hash;
       }
   }
  
  
  
  1.9       +21 -11    xml-axis/java/src/org/apache/axis/types/Month.java
  
  Index: Month.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/Month.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Month.java	5 May 2003 00:36:08 -0000	1.8
  +++ Month.java	27 Jun 2003 07:16:57 -0000	1.9
  @@ -60,10 +60,10 @@
   
   /**
    * Implementation of the XML Schema type gMonth
  - * 
  + *
    * @author Tom Jordahl <to...@macromedia.com>
    * @see <a href="http://www.w3.org/TR/xmlschema-2/#gMonth">XML Schema 3.2.14</a>
  - */ 
  + */
   public class Month implements java.io.Serializable {
       int month;
       String timezone = null;
  @@ -71,7 +71,7 @@
       /**
        * Constructs a Month with the given values
        * No timezone is specified
  -     */ 
  +     */
       public Month(int month) throws NumberFormatException {
           setValue(month);
       }
  @@ -79,21 +79,21 @@
       /**
        * Constructs a Month with the given values, including a timezone string
        * The timezone is validated but not used.
  -     */ 
  -    public Month(int month, String timezone) 
  +     */
  +    public Month(int month, String timezone)
           throws NumberFormatException {
           setValue(month, timezone);
       }
  -    
  +
       /**
        * Construct a Month from a String in the format --MM--[timezone]
  -     */ 
  +     */
       public Month(String source) throws NumberFormatException {
           if (source.length() < (6)) {
               throw new NumberFormatException(
                       Messages.getMessage("badMonth00"));
           }
  -        
  +
           if (source.charAt(0) != '-' ||
               source.charAt(1) != '-' ||
               source.charAt(4) != '-' ||
  @@ -101,7 +101,7 @@
               throw new NumberFormatException(
                       Messages.getMessage("badMonth00"));
           }
  -        
  +
           setValue(Integer.parseInt(source.substring(2,4)),
                    source.substring(6));
       }
  @@ -150,7 +150,7 @@
           setMonth(month);
           setTimezone(timezone);
       }
  -    
  +
       public void setValue(int month) throws NumberFormatException {
           setMonth(month);
       }
  @@ -176,11 +176,21 @@
           Month other = (Month) obj;
           if (obj == null) return false;
           if (this == obj) return true;
  -        
  +
           boolean equals = (this.month == other.month);
           if (timezone != null) {
               equals = equals && timezone.equals(other.timezone);
           }
           return equals;
  +    }
  +
  +    /**
  +     * Return the value of month XORed with the hashCode of timezone
  +     * iff one is defined.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        return null == timezone ? month : month ^ timezone.hashCode();
       }
   }
  
  
  
  1.9       +25 -13    xml-axis/java/src/org/apache/axis/types/MonthDay.java
  
  Index: MonthDay.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/MonthDay.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- MonthDay.java	5 May 2003 00:36:08 -0000	1.8
  +++ MonthDay.java	27 Jun 2003 07:16:57 -0000	1.9
  @@ -60,10 +60,10 @@
   
   /**
    * Implementation of the XML Schema type gMonthDay
  - * 
  + *
    * @author Tom Jordahl <to...@macromedia.com>
    * @see <a href="http://www.w3.org/TR/xmlschema-2/#gMonthDay">XML Schema 3.2.12</a>
  - */ 
  + */
   public class MonthDay implements java.io.Serializable {
       int month;
       int day;
  @@ -72,8 +72,8 @@
       /**
        * Constructs a MonthDay with the given values
        * No timezone is specified
  -     */ 
  -    public MonthDay(int month, int day) 
  +     */
  +    public MonthDay(int month, int day)
           throws NumberFormatException {
           setValue(month, day);
       }
  @@ -81,28 +81,28 @@
       /**
        * Constructs a MonthDay with the given values, including a timezone string
        * The timezone is validated but not used.
  -     */ 
  -    public MonthDay(int month, int day, String timezone) 
  +     */
  +    public MonthDay(int month, int day, String timezone)
           throws NumberFormatException {
           setValue(month, day, timezone);
       }
  -    
  +
       /**
        * Construct a MonthDay from a String in the format --MM-DD[timezone]
  -     */ 
  +     */
       public MonthDay(String source) throws NumberFormatException {
           if (source.length() < 6) {
               throw new NumberFormatException(
                       Messages.getMessage("badMonthDay00"));
           }
  -        
  +
           if (source.charAt(0) != '-' ||
               source.charAt(1) != '-' ||
               source.charAt(4) != '-' ) {
               throw new NumberFormatException(
                       Messages.getMessage("badMonthDay00"));
           }
  -        
  +
           setValue(Integer.parseInt(source.substring(2,4)),
                    Integer.parseInt(source.substring(5,7)),
                    source.substring(7));
  @@ -128,7 +128,7 @@
       /**
        * Set the day
        * NOTE: if the month isn't set yet, the day isn't validated
  -     */ 
  +     */
       public void setDay(int day) {
           // validate day
           if (day < 1 || day > 31) {
  @@ -178,7 +178,7 @@
           setDay(day);
           setTimezone(timezone);
       }
  -    
  +
       public void setValue(int month, int day) throws NumberFormatException {
           setMonth(month);
           setDay(day);
  @@ -205,11 +205,23 @@
           MonthDay other = (MonthDay) obj;
           if (obj == null) return false;
           if (this == obj) return true;
  -        
  +
           boolean equals = (this.month == other.month && this.day == other.day);
           if (timezone != null) {
               equals = equals && timezone.equals(other.timezone);
           }
           return equals;
  +    }
  +
  +    /**
  +     * Return the value of (month + day) XORed with the hashCode of
  +     * timezone iff one is defined.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        return null == timezone
  +            ? (month + day)
  +            : (month + day) ^ timezone.hashCode();
       }
   }
  
  
  
  1.5       +46 -7     xml-axis/java/src/org/apache/axis/types/NMTokens.java
  
  Index: NMTokens.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/NMTokens.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- NMTokens.java	22 Apr 2003 19:36:00 -0000	1.4
  +++ NMTokens.java	27 Jun 2003 07:16:57 -0000	1.5
  @@ -54,16 +54,19 @@
    */
   package org.apache.axis.types;
   
  +import java.util.Arrays;
  +import java.util.HashSet;
  +import java.util.Set;
   import java.util.StringTokenizer;
   
   /**
    * Custom class for supporting XSD data type NMTokens
  - * 
  + *
    * @author Davanum Srinivas <di...@yahoo.com>
    */
   public class NMTokens extends NCName {
       private NMToken[] tokens;
  -    
  +
       public NMTokens() {
           super();
       }
  @@ -85,16 +88,52 @@
       }
   
       public String toString() {
  -        String val = "";
  +        StringBuffer buf = new StringBuffer();
           for (int i = 0; i < tokens.length; i++) {
               NMToken token = tokens[i];
  -            if (i > 0) val += " ";
  -            val += token.toString();
  +            if (i > 0) buf.append(" ");
  +            buf.append(token.toString());
           }
  -        return val;
  +        return buf.toString();
       }
   
  +    /**
  +     * NMTokens can be equal without having identical ordering because
  +     * they represent a set of references.  Hence we have to compare
  +     * values here as a set, not a list.
  +     *
  +     * @param object an <code>Object</code> value
  +     * @return a <code>boolean</code> value
  +     */
       public boolean equals(Object object) {
  -        return (toString().equals(object.toString()));
  +        if (object == this) {
  +            return true;        // succeed quickly, when possible
  +        }
  +        if (object instanceof NMTokens) {
  +            NMTokens that = (NMTokens)object;
  +            if (this.tokens.length == that.tokens.length) {
  +                Set ourSet = new HashSet(Arrays.asList(this.tokens));
  +                Set theirSet = new HashSet(Arrays.asList(that.tokens));
  +                return ourSet.equals(theirSet);
  +            } else {
  +                return false;
  +            }
  +        } else {
  +            return false;
  +        }
  +    }
  +
  +    /**
  +     * Returns the sum of the hashcodes of the underlying tokens, an
  +     * operation which is not sensitive to ordering.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        int hash = 0;
  +        for (int i = 0; i < tokens.length; i++) {
  +            hash += tokens[i].hashCode();
  +        }
  +        return hash;
       }
   }
  
  
  
  1.4       +23 -0     xml-axis/java/src/org/apache/axis/types/Notation.java
  
  Index: Notation.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/Notation.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Notation.java	5 May 2003 00:36:08 -0000	1.3
  +++ Notation.java	27 Jun 2003 07:16:57 -0000	1.4
  @@ -133,6 +133,29 @@
           return true;
       }
   
  +    /**
  +     * Returns the sum of the hashcodes of {name,publicURI,systemURI}
  +     * for whichever properties in that set is non null.  This is
  +     * consistent with the implementation of equals, as required by
  +     * {@link java.lang.Object#hashCode() Object.hashCode}.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        int hash = 0;
  +        if (null != name) {
  +            hash += name.hashCode();
  +        }
  +        if (null != publicURI) {
  +            hash += publicURI.hashCode();
  +        }
  +        if (null != systemURI) {
  +            hash += systemURI.hashCode();
  +        }
  +        return hash;
  +    }
  +
  +
       // Type metadata
       private static TypeDesc typeDesc;
   
  
  
  
  1.8       +19 -10    xml-axis/java/src/org/apache/axis/types/Time.java
  
  Index: Time.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/Time.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- Time.java	5 May 2003 00:36:08 -0000	1.7
  +++ Time.java	27 Jun 2003 07:16:57 -0000	1.8
  @@ -63,11 +63,11 @@
   
   /**
    * Class that represents the xsd:time XML Schema type
  - */ 
  + */
   public class Time implements java.io.Serializable {
       private Calendar _value;
   
  -    
  +
       private static SimpleDateFormat zulu =
          new SimpleDateFormat("HH:mm:ss.SSS'Z'");
   
  @@ -79,15 +79,15 @@
   
       /**
        * Initialize with a Calender, year month and date are ignored
  -     */ 
  +     */
       public Time(Calendar value) {
           this._value = value;
           _value.set(0,0,0);      // ignore year, month, date
       }
  -    
  +
       /**
        * Converts a string formatted as HH:mm:ss[.SSS][+/-offset]
  -     */ 
  +     */
       public Time(String value) throws NumberFormatException {
           _value = makeValue(value);
       }
  @@ -100,7 +100,7 @@
           this._value = date;
           _value.set(0,0,0);      // ignore year, month, date
       }
  -    
  +
       public void setTime(Date date) {
           _value.setTime(date);
           _value.set(0,0,0);      // ignore year, month, date
  @@ -108,7 +108,7 @@
   
       /**
        * Utility function that parses xsd:time strings and returns a Date object
  -     */ 
  +     */
       private Calendar makeValue(String source) throws NumberFormatException {
           Calendar calendar = Calendar.getInstance();
           Date date;
  @@ -195,7 +195,7 @@
   
           calendar.setTime(date);
           calendar.set(0,0,0);    // ignore year, month, date
  -        
  +
           return calendar;
       }
   
  @@ -203,7 +203,7 @@
           synchronized (zulu) {
               return zulu.format(_value.getTime());
           }
  -        
  +
       }
   
       public boolean equals(Object obj) {
  @@ -219,6 +219,15 @@
                 _value.equals(other._value)));
   
           return _equals;
  -        
  +
  +    }
  +
  +    /**
  +     * Returns the hashcode of the underlying calendar.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        return _value == null ? 0 : _value.hashCode();
       }
   }
  
  
  
  1.9       +23 -13    xml-axis/java/src/org/apache/axis/types/Year.java
  
  Index: Year.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/Year.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Year.java	5 May 2003 00:36:08 -0000	1.8
  +++ Year.java	27 Jun 2003 07:16:57 -0000	1.9
  @@ -60,10 +60,10 @@
   
   /**
    * Implementation of the XML Schema type gYear
  - * 
  + *
    * @author Tom Jordahl <to...@macromedia.com>
    * @see <a href="http://www.w3.org/TR/xmlschema-2/#gYear">XML Schema 3.2.11</a>
  - */ 
  + */
   public class Year implements java.io.Serializable {
       int year;
       String timezone = null;
  @@ -71,7 +71,7 @@
       /**
        * Constructs a Year with the given values
        * No timezone is specified
  -     */ 
  +     */
       public Year(int year) throws NumberFormatException {
           setValue(year);
       }
  @@ -79,17 +79,17 @@
       /**
        * Constructs a Year with the given values, including a timezone string
        * The timezone is validated but not used.
  -     */ 
  +     */
       public Year(int year, String timezone) throws NumberFormatException {
           setValue(year, timezone);
       }
  -    
  +
       /**
        * Construct a Year from a String in the format [-]CCYY[timezone]
  -     */ 
  +     */
       public Year(String source) throws NumberFormatException {
           int negative = 0;
  -        
  +
           if (source.charAt(0) == '-') {
               negative = 1;
           }
  @@ -97,13 +97,13 @@
               throw new NumberFormatException(
                       Messages.getMessage("badYear00"));
           }
  -        
  +
           // calculate how many more than 4 digits (if any) in the year
           int pos = 4 + negative;  // skip minus sign if present
           while (pos < source.length() && Character.isDigit(source.charAt(pos))) {
               ++pos;
           }
  -        
  +
           setValue(Integer.parseInt(source.substring(0,pos)),
                    source.substring(pos));
       }
  @@ -118,7 +118,7 @@
               throw new NumberFormatException(
                       Messages.getMessage("badYear00"));
           }
  -        
  +
           this.year = year;
       }
   
  @@ -149,12 +149,12 @@
           }
       }
   
  -    public void setValue(int year, String timezone) 
  +    public void setValue(int year, String timezone)
           throws NumberFormatException {
           setYear(year);
           setTimezone(timezone);
       }
  -    
  +
       public void setValue(int year) throws NumberFormatException {
           setYear(year);
       }
  @@ -180,11 +180,21 @@
           Year other = (Year) obj;
           if (obj == null) return false;
           if (this == obj) return true;
  -        
  +
           boolean equals = (this.year == other.year);
           if (timezone != null) {
               equals = equals && timezone.equals(other.timezone);
           }
           return equals;
  +    }
  +
  +    /**
  +     * Return the value of year XORed with the hashCode of timezone
  +     * iff one is defined.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        return null == timezone ? year : year ^ timezone.hashCode();
       }
   }
  
  
  
  1.9       +24 -12    xml-axis/java/src/org/apache/axis/types/YearMonth.java
  
  Index: YearMonth.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/types/YearMonth.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- YearMonth.java	5 May 2003 00:36:08 -0000	1.8
  +++ YearMonth.java	27 Jun 2003 07:16:58 -0000	1.9
  @@ -60,10 +60,10 @@
   
   /**
    * Implementation of the XML Schema type gYearMonth
  - * 
  + *
    * @author Tom Jordahl <to...@macromedia.com>
    * @see <a href="http://www.w3.org/TR/xmlschema-2/#gYearMonth">XML Schema 3.2.10</a>
  - */ 
  + */
   public class YearMonth implements java.io.Serializable {
       int year;
       int month;
  @@ -72,7 +72,7 @@
       /**
        * Constructs a YearMonth with the given values
        * No timezone is specified
  -     */ 
  +     */
       public YearMonth(int year, int month) throws NumberFormatException {
           setValue(year, month);
       }
  @@ -80,17 +80,17 @@
       /**
        * Constructs a YearMonth with the given values, including a timezone string
        * The timezone is validated but not used.
  -     */ 
  +     */
       public YearMonth(int year, int month, String timezone) throws NumberFormatException {
           setValue(year, month, timezone);
       }
  -    
  +
       /**
        * Construct a YearMonth from a String in the format [-]CCYY-MM
  -     */ 
  +     */
       public YearMonth(String source) throws NumberFormatException {
           int negative = 0;
  -        
  +
           if (source.charAt(0) == '-') {
               negative = 1;
           }
  @@ -98,7 +98,7 @@
               throw new NumberFormatException(
                       Messages.getMessage("badYearMonth00"));
           }
  -        
  +
           // look for first '-'
           int pos = source.substring(negative).indexOf('-');
           if (pos < 0) {
  @@ -106,7 +106,7 @@
                       Messages.getMessage("badYearMonth00"));
           }
           if (negative > 0) pos++;    //adjust index for orginal string
  -        
  +
           setValue(Integer.parseInt(source.substring(0,pos)),
                    Integer.parseInt(source.substring(pos+1,pos+3)),
                    source.substring(pos+3));
  @@ -122,7 +122,7 @@
               throw new NumberFormatException(
                       Messages.getMessage("badYearMonth00"));
           }
  -        
  +
           this.year = year;
       }
   
  @@ -171,7 +171,7 @@
           setMonth(month);
           setTimezone(timezone);
       }
  -    
  +
       public void setValue(int year, int month) throws NumberFormatException {
           setYear(year);
           setMonth(month);
  @@ -202,11 +202,23 @@
           YearMonth other = (YearMonth) obj;
           if (obj == null) return false;
           if (this == obj) return true;
  -        
  +
           boolean equals = (this.year == other.year && this.month == other.month);
           if (timezone != null) {
               equals = equals && timezone.equals(other.timezone);
           }
           return equals;
  +    }
  +
  +    /**
  +     * Return the value of (month + year) XORed with the hashCode of
  +     * timezone iff one is defined.
  +     *
  +     * @return an <code>int</code> value
  +     */
  +    public int hashCode() {
  +        return null == timezone
  +            ? (month + year)
  +            : (month + year) ^ timezone.hashCode();
       }
   }