1414import javax .money .NumberValue ;
1515
1616import java .io .Serializable ;
17+ import java .math .BigDecimal ;
1718import java .util .ArrayList ;
1819import java .util .Arrays ;
1920import java .util .List ;
@@ -252,7 +253,23 @@ public String toString() {
252253 */
253254 @ Override
254255 public int hashCode () {
255- return Objects .hash (baseCurrency , conversionContext , factor , termCurrency , chain );
256+ // Numerically equal factors should produce the same hash code, so hash a normalized
257+ // version of the factor rather than the NumberValue object.
258+ BigDecimal normalizedFactor = factor .numberValue (BigDecimal .class ).stripTrailingZeros ();
259+
260+ // The exchange rate chain includes a reference to "this" if the caller doesn't explicitly
261+ // set a chain in the builder, so we can't naively hash the chain or we'll get infinite
262+ // recursion.
263+ int chainHash = 0 ;
264+ for (ExchangeRate chainedRate : chain ) {
265+ if (chainedRate == this ) {
266+ // Use a constant to represent the presence of this object in the chain.
267+ chainHash = Objects .hash (chainHash , "this" );
268+ } else {
269+ chainHash = Objects .hash (chainHash , chainedRate );
270+ }
271+ }
272+ return Objects .hash (baseCurrency , conversionContext , normalizedFactor , termCurrency , chainHash );
256273 }
257274
258275 /*
@@ -265,13 +282,11 @@ public boolean equals(Object obj) {
265282 if (obj == this ) {
266283 return true ;
267284 }
268- if (obj instanceof DefaultExchangeRate ) {
269- DefaultExchangeRate other = (DefaultExchangeRate ) obj ;
270- return Objects .equals (baseCurrency , other .baseCurrency ) &&
271- Objects .equals (conversionContext , other .conversionContext ) &&
272- Objects .equals (factor , other .factor ) && Objects .equals (termCurrency , other .termCurrency );
273- }
274- return false ;
285+ DefaultExchangeRate other = (DefaultExchangeRate ) obj ;
286+ return Objects .equals (baseCurrency , other .baseCurrency ) &&
287+ Objects .equals (conversionContext , other .conversionContext ) &&
288+ factor .compareTo (other .factor ) == 0 &&
289+ Objects .equals (termCurrency , other .termCurrency );
275290 }
276291
277292 /**
0 commit comments