Coverage Report - org.joda.money.BigMoney
 
Classes in this File Line Coverage Branch Coverage Complexity
BigMoney
99%
263/264
97%
119/122
2
 
 1  
 /*
 2  
  *  Copyright 2009-2013 Stephen Colebourne
 3  
  *
 4  
  *  Licensed under the Apache License, Version 2.0 (the "License");
 5  
  *  you may not use this file except in compliance with the License.
 6  
  *  You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  *  Unless required by applicable law or agreed to in writing, software
 11  
  *  distributed under the License is distributed on an "AS IS" BASIS,
 12  
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  *  See the License for the specific language governing permissions and
 14  
  *  limitations under the License.
 15  
  */
 16  
 package org.joda.money;
 17  
 
 18  
 import java.io.InvalidObjectException;
 19  
 import java.io.ObjectInputStream;
 20  
 import java.io.Serializable;
 21  
 import java.math.BigDecimal;
 22  
 import java.math.BigInteger;
 23  
 import java.math.RoundingMode;
 24  
 import java.util.Arrays;
 25  
 import java.util.Iterator;
 26  
 import java.util.regex.Pattern;
 27  
 
 28  
 import org.joda.convert.FromString;
 29  
 import org.joda.convert.ToString;
 30  
 
 31  
 /**
 32  
  * An amount of money with unrestricted decimal place precision.
 33  
  * <p>
 34  
  * This class represents a quantity of money, stored as a {@code BigDecimal} amount
 35  
  * in a single {@link CurrencyUnit currency}.
 36  
  * <p>
 37  
  * Every currency has a certain standard number of decimal places.
 38  
  * This is typically 2 (Euro, British Pound, US Dollar) but might be
 39  
  * 0 (Japanese Yen), 1 (Vietnamese Dong) or 3 (Bahrain Dinar).
 40  
  * The {@code BigMoney} class is not restricted to the standard decimal places
 41  
  * and can represent an amount to any precision that a {@code BigDecimal} can represent.
 42  
  * <p>
 43  
  * This class is immutable and thread-safe.
 44  
  */
 45  2
 public final class BigMoney implements BigMoneyProvider, Comparable<BigMoneyProvider>, Serializable {
 46  
 
 47  
     /**
 48  
      * The serialisation version.
 49  
      */
 50  
     private static final long serialVersionUID = 1L;
 51  
     /**
 52  
      * The regex for parsing.
 53  
      */
 54  1
     private static final Pattern PARSE_REGEX = Pattern.compile("[+-]?[0-9]*[.]?[0-9]*");
 55  
 
 56  
     /**
 57  
      * The currency, not null.
 58  
      */
 59  
     private final CurrencyUnit currency;
 60  
     /**
 61  
      * The amount, not null.
 62  
      */
 63  
     private final BigDecimal amount;
 64  
 
 65  
     //-----------------------------------------------------------------------
 66  
     /**
 67  
      * Obtains an instance of {@code BigMoney} from a {@code BigDecimal}.
 68  
      * <p>
 69  
      * This allows you to create an instance with a specific currency and amount.
 70  
      * The scale of the money will be that of the BigDecimal.
 71  
      *
 72  
      * @param currency  the currency, not null
 73  
      * @param amount  the amount of money, not null
 74  
      * @return the new instance, never null
 75  
      * @throws IllegalArgumentException if an invalid BigDecimal subclass has been used
 76  
      */
 77  
     public static BigMoney of(CurrencyUnit currency, BigDecimal amount) {
 78  458
         MoneyUtils.checkNotNull(currency, "Currency must not be null");
 79  454
         MoneyUtils.checkNotNull(amount, "Amount must not be null");
 80  453
         if (amount.getClass() != BigDecimal.class) {
 81  2
             BigInteger value = amount.unscaledValue();
 82  2
             if (value == null) {
 83  1
                 throw new IllegalArgumentException("Illegal BigDecimal subclass");
 84  
             }
 85  1
             if (value.getClass() != BigInteger.class) {
 86  1
                 value = new BigInteger(value.toString());
 87  
             }
 88  1
             amount = new BigDecimal(value, amount.scale());
 89  
         }
 90  452
         return new BigMoney(currency, amount);
 91  
     }
 92  
 
 93  
     /**
 94  
      * Obtains an instance of {@code BigMoney} from a {@code double} using a well-defined conversion.
 95  
      * <p>
 96  
      * This allows you to create an instance with a specific currency and amount.
 97  
      * <p>
 98  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 99  
      * the most expected answer for most programming scenarios.
 100  
      * Any {@code double} literal in code will be converted to
 101  
      * exactly the same BigDecimal with the same scale.
 102  
      * For example, the literal '1.425d' will be converted to '1.425'.
 103  
      * The scale of the money will be that of the BigDecimal produced.
 104  
      *
 105  
      * @param currency  the currency, not null
 106  
      * @param amount  the amount of money, not null
 107  
      * @return the new instance, never null
 108  
      */
 109  
     public static BigMoney of(CurrencyUnit currency, double amount) {
 110  7
         MoneyUtils.checkNotNull(currency, "Currency must not be null");
 111  6
         return BigMoney.of(currency, BigDecimal.valueOf(amount));
 112  
     }
 113  
 
 114  
     //-----------------------------------------------------------------------
 115  
     /**
 116  
      * Obtains an instance of {@code BigMoney} from a {@code BigDecimal} at a specific scale.
 117  
      * <p>
 118  
      * This allows you to create an instance with a specific currency and amount.
 119  
      * No rounding is performed on the amount, so it must have a
 120  
      * scale less than or equal to the new scale.
 121  
      *
 122  
      * @param currency  the currency, not null
 123  
      * @param amount  the amount of money, not null
 124  
      * @param scale  the scale to use, zero or positive
 125  
      * @return the new instance, never null
 126  
      * @throws ArithmeticException if the scale exceeds the currency scale
 127  
      */
 128  
     public static BigMoney ofScale(CurrencyUnit currency, BigDecimal amount, int scale) {
 129  5
         return BigMoney.ofScale(currency, amount, scale, RoundingMode.UNNECESSARY);
 130  
     }
 131  
 
 132  
     /**
 133  
      * Obtains an instance of {@code BigMoney} from a {@code double} using a
 134  
      * well-defined conversion, rounding as necessary.
 135  
      * <p>
 136  
      * This allows you to create an instance with a specific currency and amount.
 137  
      * If the amount has a scale in excess of the scale of the currency then the excess
 138  
      * fractional digits are rounded using the rounding mode.
 139  
      *
 140  
      * @param currency  the currency, not null
 141  
      * @param amount  the amount of money, not null
 142  
      * @param scale  the scale to use, zero or positive
 143  
      * @param roundingMode  the rounding mode to use, not null
 144  
      * @return the new instance, never null
 145  
      * @throws ArithmeticException if the rounding fails
 146  
      */
 147  
     public static BigMoney ofScale(CurrencyUnit currency, BigDecimal amount, int scale, RoundingMode roundingMode) {
 148  12
         MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null");
 149  10
         MoneyUtils.checkNotNull(amount, "Amount must not be null");
 150  8
         MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null");
 151  7
         amount = amount.setScale(scale, roundingMode);
 152  5
         return BigMoney.of(currency, amount);
 153  
     }
 154  
 
 155  
     /**
 156  
      * Obtains an instance of {@code BigMoney} from a scaled amount.
 157  
      * <p>
 158  
      * This allows you to create an instance with a specific currency, amount and scale.
 159  
      * The amount is defined in terms of the specified scale.
 160  
      * <p>
 161  
      * For example, {@code ofScale(USD, 234, 2)} creates the instance {@code USD 2.34}.
 162  
      *
 163  
      * @param currency  the currency, not null
 164  
      * @param unscaledAmount  the unscaled amount of money
 165  
      * @param scale  the scale to use
 166  
      * @return the new instance, never null
 167  
      */
 168  
     public static BigMoney ofScale(CurrencyUnit currency, long unscaledAmount, int scale) {
 169  3
         MoneyUtils.checkNotNull(currency, "Currency must not be null");
 170  2
         return BigMoney.of(currency, BigDecimal.valueOf(unscaledAmount, scale));
 171  
     }
 172  
 
 173  
     //-----------------------------------------------------------------------
 174  
     /**
 175  
      * Obtains an instance of {@code BigMoney} from an amount in major units.
 176  
      * <p>
 177  
      * This allows you to create an instance with a specific currency and amount.
 178  
      * The scale of the money will be zero.
 179  
      * <p>
 180  
      * The amount is a whole number only. Thus you can initialise the value
 181  
      * 'USD 20', but not the value 'USD 20.32'.
 182  
      * For example, {@code ofMajor(USD, 25)} creates the instance {@code USD 25}.
 183  
      *
 184  
      * @param currency  the currency, not null
 185  
      * @param amountMajor  the amount of money in the major division of the currency
 186  
      * @return the new instance, never null
 187  
      */
 188  
     public static BigMoney ofMajor(CurrencyUnit currency, long amountMajor) {
 189  3
         MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null");
 190  2
         return BigMoney.of(currency, BigDecimal.valueOf(amountMajor));
 191  
     }
 192  
 
 193  
     /**
 194  
      * Obtains an instance of {@code BigMoney} from an amount in minor units.
 195  
      * <p>
 196  
      * This allows you to create an instance with a specific currency and amount
 197  
      * expressed in terms of the minor unit.
 198  
      * The scale of the money will be that of the currency, such as 2 for USD or 0 for JPY.
 199  
      * <p>
 200  
      * For example, if constructing US Dollars, the input to this method represents cents.
 201  
      * Note that when a currency has zero decimal places, the major and minor units are the same.
 202  
      * For example, {@code ofMajor(USD, 2595)} creates the instance {@code USD 25.95}.
 203  
      *
 204  
      * @param currency  the currency, not null
 205  
      * @param amountMinor  the amount of money in the minor division of the currency
 206  
      * @return the new instance, never null
 207  
      */
 208  
     public static BigMoney ofMinor(CurrencyUnit currency, long amountMinor) {
 209  23
         MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null");
 210  21
         return BigMoney.of(currency, BigDecimal.valueOf(amountMinor, currency.getDecimalPlaces()));
 211  
     }
 212  
 
 213  
     //-----------------------------------------------------------------------
 214  
     /**
 215  
      * Obtains an instance of {@code BigMoney} representing zero.
 216  
      * <p>
 217  
      * The scale of the money will be zero.
 218  
      * For example, {@code zero(USD)} creates the instance {@code USD 0}.
 219  
      *
 220  
      * @param currency  the currency, not null
 221  
      * @return the instance representing zero, never null
 222  
      */
 223  
     public static BigMoney zero(CurrencyUnit currency) {
 224  33
         return BigMoney.of(currency, BigDecimal.ZERO);
 225  
     }
 226  
 
 227  
     /**
 228  
      * Obtains an instance of {@code BigMoney} representing zero at a specific scale.
 229  
      * <p>
 230  
      * For example, {@code zero(USD, 2)} creates the instance {@code USD 0.00}.
 231  
      *
 232  
      * @param currency  the currency, not null
 233  
      * @param scale  the scale to use, zero or positive
 234  
      * @return the instance representing zero, never null
 235  
      * @throws IllegalArgumentException if the scale is negative
 236  
      */
 237  
     public static BigMoney zero(CurrencyUnit currency, int scale) {
 238  3
         return BigMoney.of(currency, BigDecimal.valueOf(0, scale));
 239  
     }
 240  
 
 241  
     //-----------------------------------------------------------------------
 242  
     /**
 243  
      * Obtains an instance of {@code BigMoney} from a provider.
 244  
      * <p>
 245  
      * This allows you to create an instance from any class that implements the
 246  
      * provider, such as {@code Money}.
 247  
      * This method simply calls {@link BigMoneyProvider#toBigMoney()} checking for nulls.
 248  
      *
 249  
      * @param moneyProvider  the money to convert, not null
 250  
      * @return the new instance, never null
 251  
      */
 252  
     public static BigMoney of(BigMoneyProvider moneyProvider) {
 253  607
         MoneyUtils.checkNotNull(moneyProvider, "BigMoneyProvider must not be null");
 254  574
         BigMoney money = moneyProvider.toBigMoney();
 255  574
         MoneyUtils.checkNotNull(money, "BigMoneyProvider must not return null");
 256  563
         return money;
 257  
     }
 258  
 
 259  
     //-----------------------------------------------------------------------
 260  
     /**
 261  
      * Obtains an instance of {@code BigMoney} as the total value of an array.
 262  
      * <p>
 263  
      * The array must contain at least one monetary value.
 264  
      * Subsequent amounts are added as though using {@link #plus(BigMoneyProvider)}.
 265  
      * All amounts must be in the same currency.
 266  
      * 
 267  
      * @param monies  the monetary values to total, not empty, no null elements, not null
 268  
      * @return the total, never null
 269  
      * @throws IllegalArgumentException if the array is empty
 270  
      * @throws CurrencyMismatchException if the currencies differ
 271  
      */
 272  
     public static BigMoney total(BigMoneyProvider... monies) {
 273  15
         MoneyUtils.checkNotNull(monies, "Money array must not be null");
 274  15
         if (monies.length == 0) {
 275  2
             throw new IllegalArgumentException("Money array must not be empty");
 276  
         }
 277  13
         BigMoney total = of(monies[0]);
 278  9
         MoneyUtils.checkNotNull(total, "Money arary must not contain null entries");
 279  15
         for (int i = 1; i < monies.length; i++) {
 280  10
             total = total.plus(of(monies[i]));
 281  
         }
 282  5
         return total;
 283  
     }
 284  
 
 285  
     /**
 286  
      * Obtains an instance of {@code BigMoney} as the total value of a collection.
 287  
      * <p>
 288  
      * The iterable must provide at least one monetary value.
 289  
      * Subsequent amounts are added as though using {@link #plus(BigMoneyProvider)}.
 290  
      * All amounts must be in the same currency.
 291  
      * 
 292  
      * @param monies  the monetary values to total, not empty, no null elements, not null
 293  
      * @return the total, never null
 294  
      * @throws IllegalArgumentException if the iterable is empty
 295  
      * @throws CurrencyMismatchException if the currencies differ
 296  
      */
 297  
     public static BigMoney total(Iterable<? extends BigMoneyProvider> monies) {
 298  7
         MoneyUtils.checkNotNull(monies, "Money iterator must not be null");
 299  7
         Iterator<? extends BigMoneyProvider> it = monies.iterator();
 300  7
         if (it.hasNext() == false) {
 301  1
             throw new IllegalArgumentException("Money iterator must not be empty");
 302  
         }
 303  6
         BigMoney total = of(it.next());
 304  4
         MoneyUtils.checkNotNull(total, "Money iterator must not contain null entries");
 305  7
         while (it.hasNext()) {
 306  5
             total = total.plus(it.next());
 307  
         }
 308  2
         return total;
 309  
     }
 310  
 
 311  
     /**
 312  
      * Obtains an instance of {@code Money} as the total value of
 313  
      * a possibly empty array.
 314  
      * <p>
 315  
      * The amounts are added as though using {@link #plus(BigMoneyProvider)} starting
 316  
      * from zero in the specified currency.
 317  
      * All amounts must be in the same currency.
 318  
      * 
 319  
      * @param currency  the currency to total in, not null
 320  
      * @param monies  the monetary values to total, no null elements, not null
 321  
      * @return the total, never null
 322  
      * @throws CurrencyMismatchException if the currencies differ
 323  
      */
 324  
     public static BigMoney total(CurrencyUnit currency, BigMoneyProvider... monies) {
 325  19
         return BigMoney.zero(currency).plus(Arrays.asList(monies));
 326  
     }
 327  
 
 328  
     /**
 329  
      * Obtains an instance of {@code Money} as the total value of
 330  
      * a possibly empty collection.
 331  
      * <p>
 332  
      * The amounts are added as though using {@link #plus(BigMoneyProvider)} starting
 333  
      * from zero in the specified currency.
 334  
      * All amounts must be in the same currency.
 335  
      * 
 336  
      * @param currency  the currency to total in, not null
 337  
      * @param monies  the monetary values to total, no null elements, not null
 338  
      * @return the total, never null
 339  
      * @throws CurrencyMismatchException if the currencies differ
 340  
      */
 341  
     public static BigMoney total(CurrencyUnit currency, Iterable<? extends BigMoneyProvider> monies) {
 342  8
         return BigMoney.zero(currency).plus(monies);
 343  
     }
 344  
 
 345  
     //-----------------------------------------------------------------------
 346  
     /**
 347  
      * Parses an instance of {@code BigMoney} from a string.
 348  
      * <p>
 349  
      * The string format is '<currencyCode> <amount>'.
 350  
      * The currency code must be a valid three letter currency.
 351  
      * The amount must match the regular expression {@code [+-]?[0-9]*[.]?[0-9]*}.
 352  
      * This matches the output from {@link #toString()}.
 353  
      * <p>
 354  
      * For example, {@code parse("USD 25")} creates the instance {@code USD 25}
 355  
      * while {@code parse("USD 25.95")} creates the instance {@code USD 25.95}.
 356  
      *
 357  
      * @param moneyStr  the money string to parse, not null
 358  
      * @return the parsed instance, never null
 359  
      * @throws IllegalArgumentException if the string is malformed
 360  
      * @throws ArithmeticException if the amount is too large
 361  
      */
 362  
     @FromString
 363  
     public static BigMoney parse(String moneyStr) {
 364  127
         MoneyUtils.checkNotNull(moneyStr, "Money must not be null");
 365  125
         if (moneyStr.length() < 5 || moneyStr.charAt(3) != ' ') {
 366  4
             throw new IllegalArgumentException("Money '" + moneyStr + "' cannot be parsed");
 367  
         }
 368  121
         String currStr = moneyStr.substring(0, 3);
 369  121
         String amountStr = moneyStr.substring(4);
 370  121
         if (PARSE_REGEX.matcher(amountStr).matches() == false) {
 371  1
             throw new IllegalArgumentException("Money amount '" + moneyStr + "' cannot be parsed");
 372  
         }
 373  120
         return BigMoney.of(CurrencyUnit.of(currStr), new BigDecimal(amountStr));
 374  
     }
 375  
 
 376  
     //-----------------------------------------------------------------------
 377  
     /**
 378  
      * Ensures that a {@code BigMoney} is not {@code null}.
 379  
      * <p>
 380  
      * If the input money is not {@code null}, then it is returned, providing
 381  
      * that the currency matches the specified currency.
 382  
      * If the input money is {@code null}, then zero money in the currency
 383  
      * is returned with a scale of zero.
 384  
      * 
 385  
      * @param money  the monetary value to check, may be null
 386  
      * @param currency  the currency to use, not null
 387  
      * @return the input money or zero in the specified currency, never null
 388  
      * @throws CurrencyMismatchException if the input money is non-null and the currencies differ
 389  
      */
 390  
     public static BigMoney nonNull(BigMoney money, CurrencyUnit currency) {
 391  5
         if (money == null) {
 392  2
             return zero(currency);
 393  
         }
 394  3
         if (money.getCurrencyUnit().equals(currency) == false) {
 395  2
             MoneyUtils.checkNotNull(currency, "Currency must not be null");
 396  1
             throw new CurrencyMismatchException(money.getCurrencyUnit(), currency);
 397  
         }
 398  1
         return money;
 399  
     }
 400  
 
 401  
     //-----------------------------------------------------------------------
 402  
     /**
 403  
      * Constructor, creating a new monetary instance.
 404  
      * 
 405  
      * @param currency  the currency to use, not null
 406  
      * @param amount  the amount of money, not null
 407  
      */
 408  491
     BigMoney(CurrencyUnit currency, BigDecimal amount) {
 409  491
         assert currency != null : "Joda-Money bug: Currency must not be null";
 410  490
         assert amount != null : "Joda-Money bug: Amount must not be null";
 411  489
         this.currency = currency;
 412  489
         this.amount = amount;
 413  489
     }
 414  
 
 415  
     /**
 416  
      * Block malicious data streams.
 417  
      * 
 418  
      * @param ois  the input stream, not null
 419  
      * @throws InvalidObjectException
 420  
      */
 421  
     private void readObject(ObjectInputStream ois) throws InvalidObjectException {
 422  0
         throw new InvalidObjectException("Serialization delegate required");
 423  
     }
 424  
 
 425  
     /**
 426  
      * Uses a serialization delegate.
 427  
      * 
 428  
      * @return the replacing object, never null
 429  
      */
 430  
     private Object writeReplace() {
 431  3
         return new Ser(Ser.BIG_MONEY, this);
 432  
     }
 433  
 
 434  
     //-----------------------------------------------------------------------
 435  
     /**
 436  
      * Returns a new {@code BigMoney}, returning {@code this} if possible.
 437  
      * <p>
 438  
      * This instance is immutable and unaffected by this method.
 439  
      * 
 440  
      * @param newAmount  the new amount to use, not null
 441  
      * @return the new instance, never null
 442  
      */
 443  
     private BigMoney with(BigDecimal newAmount) {
 444  34
         if (newAmount == amount) {
 445  6
             return this;
 446  
         }
 447  28
         return new BigMoney(currency, newAmount);
 448  
     }
 449  
 
 450  
     //-----------------------------------------------------------------------
 451  
     /**
 452  
      * Gets the currency.
 453  
      * 
 454  
      * @return the currency, never null
 455  
      */
 456  
     public CurrencyUnit getCurrencyUnit() {
 457  555
         return currency;
 458  
     }
 459  
 
 460  
     //-----------------------------------------------------------------------
 461  
     /**
 462  
      * Returns a copy of this monetary value with the specified currency.
 463  
      * <p>
 464  
      * The returned instance will have the specified currency and the amount
 465  
      * from this instance. No currency conversion or alteration to the scale occurs.
 466  
      * <p>
 467  
      * This instance is immutable and unaffected by this method.
 468  
      * 
 469  
      * @param currency  the currency to use, not null
 470  
      * @return the new instance with the input currency set, never null
 471  
      */
 472  
     public BigMoney withCurrencyUnit(CurrencyUnit currency) {
 473  13
         MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null");
 474  10
         if (this.currency == currency) {
 475  3
             return this;
 476  
         }
 477  7
         return new BigMoney(currency, amount);
 478  
     }
 479  
 
 480  
     //-----------------------------------------------------------------------
 481  
     /**
 482  
      * Gets the scale of the {@code BigDecimal} amount.
 483  
      * <p>
 484  
      * The scale has the same meaning as in {@link BigDecimal}.
 485  
      * Positive values represent the number of decimal places in use.
 486  
      * Negative numbers represent the opposite.
 487  
      * For example, a scale of 2 means that the money will have two decimal places
 488  
      * such as 'USD 43.25'. Whereas, a scale of -3 means that only thousands can be
 489  
      * represented, such as 'GBP 124000'.
 490  
      * 
 491  
      * @return the scale in use
 492  
      * @see #withScale
 493  
      */
 494  
     public int getScale() {
 495  166
         return amount.scale();
 496  
     }
 497  
 
 498  
     /**
 499  
      * Checks if this money has the scale of the currency.
 500  
      * <p>
 501  
      * Each currency has a default scale, such as 2 for USD and 0 for JPY.
 502  
      * This method checks if the current scale matches the default scale.
 503  
      * 
 504  
      * @return true if the scale equals the current default scale
 505  
      */
 506  
     public boolean isCurrencyScale() {
 507  217
         return amount.scale() == currency.getDecimalPlaces();
 508  
     }
 509  
 
 510  
     //-----------------------------------------------------------------------
 511  
     /**
 512  
      * Returns a copy of this monetary value with the specified scale,
 513  
      * truncating the amount if necessary.
 514  
      * <p>
 515  
      * The returned instance will have this currency and the new scaled amount.
 516  
      * For example, scaling 'USD 43.271' to a scale of 1 will yield 'USD 43.2'.
 517  
      * No rounding is performed on the amount, so it must have a
 518  
      * scale less than or equal to the new scale.
 519  
      * <p>
 520  
      * This instance is immutable and unaffected by this method.
 521  
      * 
 522  
      * @param scale  the scale to use
 523  
      * @return the new instance with the input amount set, never null
 524  
      * @throws ArithmeticException if the rounding fails
 525  
      */
 526  
     public BigMoney withScale(int scale) {
 527  3
         return withScale(scale, RoundingMode.UNNECESSARY);
 528  
     }
 529  
 
 530  
     /**
 531  
      * Returns a copy of this monetary value with the specified scale,
 532  
      * using the specified rounding mode if necessary.
 533  
      * <p>
 534  
      * The returned instance will have this currency and the new scaled amount.
 535  
      * For example, scaling 'USD 43.271' to a scale of 1 with HALF_EVEN rounding
 536  
      * will yield 'USD 43.3'.
 537  
      * <p>
 538  
      * This instance is immutable and unaffected by this method.
 539  
      * 
 540  
      * @param scale  the scale to use
 541  
      * @param roundingMode  the rounding mode to use, not null
 542  
      * @return the new instance with the input amount set, never null
 543  
      * @throws ArithmeticException if the rounding fails
 544  
      */
 545  
     public BigMoney withScale(int scale, RoundingMode roundingMode) {
 546  110
         MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null");
 547  106
         if (scale == amount.scale()) {
 548  68
             return this;
 549  
         }
 550  38
         return BigMoney.of(currency, amount.setScale(scale, roundingMode));
 551  
     }
 552  
 
 553  
     //-----------------------------------------------------------------------
 554  
     /**
 555  
      * Returns a copy of this monetary value with the scale of the currency,
 556  
      * truncating the amount if necessary.
 557  
      * <p>
 558  
      * The returned instance will have this currency and the new scaled amount.
 559  
      * For example, scaling 'USD 43.271' will yield 'USD 43.27' as USD has a scale of 2.
 560  
      * No rounding is performed on the amount, so it must have a
 561  
      * scale less than or equal to the new scale.
 562  
      * <p>
 563  
      * This instance is immutable and unaffected by this method.
 564  
      * 
 565  
      * @return the new instance with the input amount set, never null
 566  
      * @throws ArithmeticException if the rounding fails
 567  
      */
 568  
     public BigMoney withCurrencyScale() {
 569  3
         return withScale(currency.getDecimalPlaces(), RoundingMode.UNNECESSARY);
 570  
     }
 571  
 
 572  
     /**
 573  
      * Returns a copy of this monetary value with the scale of the currency,
 574  
      * using the specified rounding mode if necessary.
 575  
      * <p>
 576  
      * The returned instance will have this currency and the new scaled amount.
 577  
      * For example, scaling 'USD 43.271' will yield 'USD 43.27' as USD has a scale of 2.
 578  
      * <p>
 579  
      * This instance is immutable and unaffected by this method.
 580  
      * 
 581  
      * @param roundingMode  the rounding mode to use, not null
 582  
      * @return the new instance with the input amount set, never null
 583  
      * @throws ArithmeticException if the rounding fails
 584  
      */
 585  
     public BigMoney withCurrencyScale(RoundingMode roundingMode) {
 586  99
         return withScale(currency.getDecimalPlaces(), roundingMode);
 587  
     }
 588  
 
 589  
     //-----------------------------------------------------------------------
 590  
     /**
 591  
      * Gets the amount.
 592  
      * <p>
 593  
      * This returns the value of the money as a {@code BigDecimal}.
 594  
      * The scale will be the scale of this money.
 595  
      * 
 596  
      * @return the amount, never null
 597  
      */
 598  
     public BigDecimal getAmount() {
 599  158
         return amount;
 600  
     }
 601  
 
 602  
     /**
 603  
      * Gets the amount in major units as a {@code BigDecimal} with scale 0.
 604  
      * <p>
 605  
      * This returns the monetary amount in terms of the major units of the currency,
 606  
      * truncating the amount if necessary.
 607  
      * For example, 'EUR 2.35' will return 2, and 'BHD -1.345' will return -1.
 608  
      * <p>
 609  
      * This is returned as a {@code BigDecimal} rather than a {@code BigInteger}.
 610  
      * This is to allow further calculations to be performed on the result.
 611  
      * Should you need a {@code BigInteger}, simply call {@link BigDecimal#toBigInteger()}.
 612  
      * 
 613  
      * @return the major units part of the amount, never null
 614  
      */
 615  
     public BigDecimal getAmountMajor() {
 616  20
         return amount.setScale(0, RoundingMode.DOWN);
 617  
     }
 618  
 
 619  
     /**
 620  
      * Gets the amount in major units as a {@code long}.
 621  
      * <p>
 622  
      * This returns the monetary amount in terms of the major units of the currency,
 623  
      * truncating the amount if necessary.
 624  
      * For example, 'EUR 2.35' will return 2, and 'BHD -1.345' will return -1.
 625  
      * 
 626  
      * @return the major units part of the amount
 627  
      * @throws ArithmeticException if the amount is too large for a {@code long}
 628  
      */
 629  
     public long getAmountMajorLong() {
 630  8
         return getAmountMajor().longValueExact();
 631  
     }
 632  
 
 633  
     /**
 634  
      * Gets the amount in major units as an {@code int}.
 635  
      * <p>
 636  
      * This returns the monetary amount in terms of the major units of the currency,
 637  
      * truncating the amount if necessary.
 638  
      * For example, 'EUR 2.35' will return 2, and 'BHD -1.345' will return -1.
 639  
      * 
 640  
      * @return the major units part of the amount
 641  
      * @throws ArithmeticException if the amount is too large for an {@code int}
 642  
      */
 643  
     public int getAmountMajorInt() {
 644  8
         return getAmountMajor().intValueExact();
 645  
     }
 646  
 
 647  
     /**
 648  
      * Gets the amount in minor units as a {@code BigDecimal} with scale 0.
 649  
      * <p>
 650  
      * This returns the monetary amount in terms of the minor units of the currency,
 651  
      * truncating the amount if necessary.
 652  
      * For example, 'EUR 2.35' will return 235, and 'BHD -1.345' will return -1345.
 653  
      * <p>
 654  
      * This is returned as a {@code BigDecimal} rather than a {@code BigInteger}.
 655  
      * This is to allow further calculations to be performed on the result.
 656  
      * Should you need a {@code BigInteger}, simply call {@link BigDecimal#toBigInteger()}.
 657  
      * 
 658  
      * @return the minor units part of the amount, never null
 659  
      */
 660  
     public BigDecimal getAmountMinor() {
 661  69
         int cdp = getCurrencyUnit().getDecimalPlaces();
 662  69
         return amount.setScale(cdp, RoundingMode.DOWN).movePointRight(cdp);
 663  
     }
 664  
 
 665  
     /**
 666  
      * Gets the amount in minor units as a {@code long}.
 667  
      * <p>
 668  
      * This returns the monetary amount in terms of the minor units of the currency,
 669  
      * truncating the amount if necessary.
 670  
      * For example, 'EUR 2.35' will return 235, and 'BHD -1.345' will return -1345.
 671  
      * 
 672  
      * @return the minor units part of the amount
 673  
      * @throws ArithmeticException if the amount is too large for a {@code long}
 674  
      */
 675  
     public long getAmountMinorLong() {
 676  8
         return getAmountMinor().longValueExact();
 677  
     }
 678  
 
 679  
     /**
 680  
      * Gets the amount in minor units as an {@code int}.
 681  
      * <p>
 682  
      * This returns the monetary amount in terms of the minor units of the currency,
 683  
      * truncating the amount if necessary.
 684  
      * For example, 'EUR 2.35' will return 235, and 'BHD -1.345' will return -1345.
 685  
      * 
 686  
      * @return the minor units part of the amount
 687  
      * @throws ArithmeticException if the amount is too large for an {@code int}
 688  
      */
 689  
     public int getAmountMinorInt() {
 690  57
         return getAmountMinor().intValueExact();
 691  
     }
 692  
 
 693  
     /**
 694  
      * Gets the minor part of the amount.
 695  
      * <p>
 696  
      * This return the minor unit part of the monetary amount.
 697  
      * This is defined as the amount in minor units excluding major units.
 698  
      * <p>
 699  
      * For example, EUR has a scale of 2, so the minor part is always between 0 and 99
 700  
      * for positive amounts, and 0 and -99 for negative amounts.
 701  
      * Thus 'EUR 2.35' will return 35, and 'EUR -1.34' will return -34.
 702  
      * 
 703  
      * @return the minor part of the amount, negative if the amount is negative
 704  
      */
 705  
     public int getMinorPart() {
 706  4
         int cdp = getCurrencyUnit().getDecimalPlaces();
 707  4
         return amount.setScale(cdp, RoundingMode.DOWN)
 708  
                     .remainder(BigDecimal.ONE)
 709  
                     .movePointRight(cdp).intValueExact();
 710  
     }
 711  
 
 712  
     //-----------------------------------------------------------------------
 713  
     /**
 714  
      * Checks if the amount is zero.
 715  
      * 
 716  
      * @return true if the amount is zero
 717  
      */
 718  
     public boolean isZero() {
 719  22
         return amount.compareTo(BigDecimal.ZERO) == 0;
 720  
     }
 721  
 
 722  
     /**
 723  
      * Checks if the amount is greater than zero.
 724  
      * 
 725  
      * @return true if the amount is greater than zero
 726  
      */
 727  
     public boolean isPositive() {
 728  12
         return amount.compareTo(BigDecimal.ZERO) > 0;
 729  
     }
 730  
 
 731  
     /**
 732  
      * Checks if the amount is zero or greater.
 733  
      * 
 734  
      * @return true if the amount is zero or greater
 735  
      */
 736  
     public boolean isPositiveOrZero() {
 737  12
         return amount.compareTo(BigDecimal.ZERO) >= 0;
 738  
     }
 739  
 
 740  
     /**
 741  
      * Checks if the amount is less than zero.
 742  
      * 
 743  
      * @return true if the amount is less than zero
 744  
      */
 745  
     public boolean isNegative() {
 746  53
         return amount.compareTo(BigDecimal.ZERO) < 0;
 747  
     }
 748  
 
 749  
     /**
 750  
      * Checks if the amount is zero or less.
 751  
      * 
 752  
      * @return true if the amount is zero or less
 753  
      */
 754  
     public boolean isNegativeOrZero() {
 755  12
         return amount.compareTo(BigDecimal.ZERO) <= 0;
 756  
     }
 757  
 
 758  
     //-----------------------------------------------------------------------
 759  
     /**
 760  
      * Returns a copy of this monetary value with the specified amount.
 761  
      * <p>
 762  
      * The returned instance will have this currency and the new amount.
 763  
      * The scale of the returned instance will be that of the specified BigDecimal.
 764  
      * <p>
 765  
      * This instance is immutable and unaffected by this method.
 766  
      * 
 767  
      * @param amount  the monetary amount to set in the returned instance, not null
 768  
      * @return the new instance with the input amount set, never null
 769  
      */
 770  
     public BigMoney withAmount(BigDecimal amount) {
 771  23
         MoneyUtils.checkNotNull(amount, "Amount must not be null");
 772  20
         if (this.amount.equals(amount)) {
 773  8
             return this;
 774  
         }
 775  12
         return BigMoney.of(currency, amount);
 776  
     }
 777  
 
 778  
     /**
 779  
      * Returns a copy of this monetary value with the specified amount using a well-defined
 780  
      * conversion from a {@code double}.
 781  
      * <p>
 782  
      * The returned instance will have this currency and the new amount.
 783  
      * <p>
 784  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 785  
      * the most expected answer for most programming scenarios.
 786  
      * Any {@code double} literal in code will be converted to
 787  
      * exactly the same BigDecimal with the same scale.
 788  
      * For example, the literal '1.425d' will be converted to '1.425'.
 789  
      * The scale of the money will be that of the BigDecimal produced.
 790  
      * <p>
 791  
      * This instance is immutable and unaffected by this method.
 792  
      * 
 793  
      * @param amount  the monetary amount to set in the returned instance
 794  
      * @return the new instance with the input amount set, never null
 795  
      */
 796  
     public BigMoney withAmount(double amount) {
 797  9
         return withAmount(BigDecimal.valueOf(amount));
 798  
     }
 799  
 
 800  
     //-----------------------------------------------------------------------
 801  
     /**
 802  
      * Validates that the currency of this money and the specified money match.
 803  
      * 
 804  
      * @param moneyProvider  the money to check, not null
 805  
      * @throws CurrencyMismatchException if the currencies differ
 806  
      */
 807  
     private BigMoney checkCurrencyEqual(BigMoneyProvider moneyProvider) {
 808  186
         BigMoney money = of(moneyProvider);
 809  154
         if (isSameCurrency(money) == false) {
 810  30
             throw new CurrencyMismatchException(getCurrencyUnit(), money.getCurrencyUnit());
 811  
         }
 812  124
         return money;
 813  
     }
 814  
 
 815  
     //-----------------------------------------------------------------------
 816  
     /**
 817  
      * Returns a copy of this monetary value with a collection of monetary amounts added.
 818  
      * <p>
 819  
      * This adds the specified amounts to this monetary amount, returning a new object.
 820  
      * The amounts are added as though using {@link #plus(BigMoneyProvider)}.
 821  
      * The amounts must be in the same currency.
 822  
      * <p>
 823  
      * This instance is immutable and unaffected by this method.
 824  
      * 
 825  
      * @param moniesToAdd  the monetary values to add, no null elements, not null
 826  
      * @return the new instance with the input amounts added, never null
 827  
      * @throws CurrencyMismatchException if the currencies differ
 828  
      */
 829  
     public BigMoney plus(Iterable<? extends BigMoneyProvider> moniesToAdd) {
 830  61
         BigDecimal total = amount;
 831  61
         for (BigMoneyProvider moneyProvider : moniesToAdd) {
 832  93
             BigMoney money = checkCurrencyEqual(moneyProvider);
 833  61
             total = total.add(money.amount);
 834  61
         }
 835  27
         return with(total);
 836  
     }
 837  
 
 838  
     //-----------------------------------------------------------------------
 839  
     /**
 840  
      * Returns a copy of this monetary value with the amount added.
 841  
      * <p>
 842  
      * This adds the specified amount to this monetary amount, returning a new object.
 843  
      * The amount added must be in the same currency.
 844  
      * <p>
 845  
      * No precision is lost in the result.
 846  
      * The scale of the result will be the maximum of the two scales.
 847  
      * For example, 'USD 25.95' plus 'USD 3.021' gives 'USD 28.971'.
 848  
      * <p>
 849  
      * This instance is immutable and unaffected by this method.
 850  
      * 
 851  
      * @param moneyToAdd  the monetary value to add, not null
 852  
      * @return the new instance with the input amount added, never null
 853  
      * @throws CurrencyMismatchException if the currencies differ
 854  
      */
 855  
     public BigMoney plus(BigMoneyProvider moneyToAdd) {
 856  42
         BigMoney toAdd = checkCurrencyEqual(moneyToAdd);
 857  25
         return plus(toAdd.getAmount());
 858  
     }
 859  
 
 860  
     /**
 861  
      * Returns a copy of this monetary value with the amount added.
 862  
      * <p>
 863  
      * This adds the specified amount to this monetary amount, returning a new object.
 864  
      * <p>
 865  
      * No precision is lost in the result.
 866  
      * The scale of the result will be the maximum of the two scales.
 867  
      * For example, 'USD 25.95' plus '3.021' gives 'USD 28.971'.
 868  
      * <p>
 869  
      * This instance is immutable and unaffected by this method.
 870  
      * 
 871  
      * @param amountToAdd  the monetary value to add, not null
 872  
      * @return the new instance with the input amount added, never null
 873  
      */
 874  
     public BigMoney plus(BigDecimal amountToAdd) {
 875  30
         MoneyUtils.checkNotNull(amountToAdd, "Amount must not be null");
 876  29
         if (amountToAdd.compareTo(BigDecimal.ZERO) == 0) {
 877  3
             return this;
 878  
         }
 879  26
         BigDecimal newAmount = amount.add(amountToAdd);
 880  26
         return BigMoney.of(currency, newAmount);
 881  
     }
 882  
 
 883  
     /**
 884  
      * Returns a copy of this monetary value with the amount added.
 885  
      * <p>
 886  
      * This adds the specified amount to this monetary amount, returning a new object.
 887  
      * <p>
 888  
      * No precision is lost in the result.
 889  
      * The scale of the result will be the maximum of the two scales.
 890  
      * For example, 'USD 25.95' plus '3.021d' gives 'USD 28.971'.
 891  
      * <p>
 892  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 893  
      * the most expected answer for most programming scenarios.
 894  
      * Any {@code double} literal in code will be converted to
 895  
      * exactly the same BigDecimal with the same scale.
 896  
      * For example, the literal '1.45d' will be converted to '1.45'.
 897  
      * <p>
 898  
      * This instance is immutable and unaffected by this method.
 899  
      * 
 900  
      * @param amountToAdd  the monetary value to add, not null
 901  
      * @return the new instance with the input amount added, never null
 902  
      */
 903  
     public BigMoney plus(double amountToAdd) {
 904  4
         if (amountToAdd == 0) {
 905  1
             return this;
 906  
         }
 907  3
         BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd));
 908  3
         return BigMoney.of(currency, newAmount);
 909  
     }
 910  
 
 911  
     /**
 912  
      * Returns a copy of this monetary value with the amount in major units added.
 913  
      * <p>
 914  
      * This adds the specified amount in major units to this monetary amount,
 915  
      * returning a new object. The minor units will be untouched in the result.
 916  
      * <p>
 917  
      * No precision is lost in the result.
 918  
      * The scale of the result will be the maximum of the current scale and 0.
 919  
      * For example, 'USD 23.45' plus '138' gives 'USD 161.45'.
 920  
      * <p>
 921  
      * This instance is immutable and unaffected by this method.
 922  
      * 
 923  
      * @param amountToAdd  the monetary value to add, not null
 924  
      * @return the new instance with the input amount added, never null
 925  
      */
 926  
     public BigMoney plusMajor(long amountToAdd) {
 927  6
         if (amountToAdd == 0) {
 928  2
             return this;
 929  
         }
 930  4
         BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd));
 931  4
         return BigMoney.of(currency, newAmount);
 932  
     }
 933  
 
 934  
     /**
 935  
      * Returns a copy of this monetary value with the amount in minor units added.
 936  
      * <p>
 937  
      * This adds the specified amount in minor units to this monetary amount,
 938  
      * returning a new object.
 939  
      * <p>
 940  
      * No precision is lost in the result.
 941  
      * The scale of the result will be the maximum of the current scale and the default currency scale.
 942  
      * For example, 'USD 23.45' plus '138' gives 'USD 24.83'.
 943  
      * <p>
 944  
      * This instance is immutable and unaffected by this method.
 945  
      * 
 946  
      * @param amountToAdd  the monetary value to add, not null
 947  
      * @return the new instance with the input amount added, never null
 948  
      */
 949  
     public BigMoney plusMinor(long amountToAdd) {
 950  7
         if (amountToAdd == 0) {
 951  2
             return this;
 952  
         }
 953  5
         BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd, currency.getDecimalPlaces()));
 954  5
         return BigMoney.of(currency, newAmount);
 955  
     }
 956  
 
 957  
     //-----------------------------------------------------------------------
 958  
     /**
 959  
      * Returns a copy of this monetary value with the amount in the same currency added
 960  
      * retaining the scale by rounding the result.
 961  
      * <p>
 962  
      * The scale of the result will be the same as the scale of this instance.
 963  
      * For example,'USD 25.95' plus 'USD 3.021' gives 'USD 28.97' with most rounding modes.
 964  
      * <p>
 965  
      * This instance is immutable and unaffected by this method.
 966  
      * 
 967  
      * @param moneyToAdd  the monetary value to add, not null
 968  
      * @param roundingMode  the rounding mode to use to adjust the scale, not null
 969  
      * @return the new instance with the input amount added, never null
 970  
      */
 971  
     public BigMoney plusRetainScale(BigMoneyProvider moneyToAdd, RoundingMode roundingMode) {
 972  6
         BigMoney toAdd = checkCurrencyEqual(moneyToAdd);
 973  6
         return plusRetainScale(toAdd.getAmount(), roundingMode);
 974  
     }
 975  
 
 976  
     /**
 977  
      * Returns a copy of this monetary value with the amount added retaining
 978  
      * the scale by rounding the result.
 979  
      * <p>
 980  
      * The scale of the result will be the same as the scale of this instance.
 981  
      * For example,'USD 25.95' plus '3.021' gives 'USD 28.97' with most rounding modes.
 982  
      * <p>
 983  
      * This instance is immutable and unaffected by this method.
 984  
      * 
 985  
      * @param amountToAdd  the monetary value to add, not null
 986  
      * @param roundingMode  the rounding mode to use to adjust the scale, not null
 987  
      * @return the new instance with the input amount added, never null
 988  
      */
 989  
     public BigMoney plusRetainScale(BigDecimal amountToAdd, RoundingMode roundingMode) {
 990  26
         MoneyUtils.checkNotNull(amountToAdd, "Amount must not be null");
 991  22
         if (amountToAdd.compareTo(BigDecimal.ZERO) == 0) {
 992  4
             return this;
 993  
         }
 994  18
         BigDecimal newAmount = amount.add(amountToAdd);
 995  18
         newAmount = newAmount.setScale(getScale(), roundingMode);
 996  11
         return BigMoney.of(currency, newAmount);
 997  
     }
 998  
 
 999  
     /**
 1000  
      * Returns a copy of this monetary value with the amount added retaining
 1001  
      * the scale by rounding the result.
 1002  
      * <p>
 1003  
      * The scale of the result will be the same as the scale of this instance.
 1004  
      * For example,'USD 25.95' plus '3.021d' gives 'USD 28.97' with most rounding modes.
 1005  
      * <p>
 1006  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 1007  
      * the most expected answer for most programming scenarios.
 1008  
      * Any {@code double} literal in code will be converted to
 1009  
      * exactly the same BigDecimal with the same scale.
 1010  
      * For example, the literal '1.45d' will be converted to '1.45'.
 1011  
      * <p>
 1012  
      * This instance is immutable and unaffected by this method.
 1013  
      * 
 1014  
      * @param amountToAdd  the monetary value to add, not null
 1015  
      * @param roundingMode  the rounding mode to use to adjust the scale, not null
 1016  
      * @return the new instance with the input amount added, never null
 1017  
      */
 1018  
     public BigMoney plusRetainScale(double amountToAdd, RoundingMode roundingMode) {
 1019  16
         if (amountToAdd == 0) {
 1020  3
             return this;
 1021  
         }
 1022  13
         BigDecimal newAmount = amount.add(BigDecimal.valueOf(amountToAdd));
 1023  13
         newAmount = newAmount.setScale(getScale(), roundingMode);
 1024  8
         return BigMoney.of(currency, newAmount);
 1025  
     }
 1026  
 
 1027  
     //-----------------------------------------------------------------------
 1028  
     /**
 1029  
      * Returns a copy of this monetary value with a collection of monetary amounts subtracted.
 1030  
      * <p>
 1031  
      * This subtracts the specified amounts from this monetary amount, returning a new object.
 1032  
      * The amounts are subtracted one by one as though using {@link #minus(BigMoneyProvider)}.
 1033  
      * The amounts must be in the same currency.
 1034  
      * <p>
 1035  
      * This instance is immutable and unaffected by this method.
 1036  
      * 
 1037  
      * @param moniesToSubtract  the monetary values to subtract, no null elements, not null
 1038  
      * @return the new instance with the input amounts subtracted, never null
 1039  
      * @throws CurrencyMismatchException if the currencies differ
 1040  
      */
 1041  
     public BigMoney minus(Iterable<? extends BigMoneyProvider> moniesToSubtract) {
 1042  14
         BigDecimal total = amount;
 1043  14
         for (BigMoneyProvider moneyProvider : moniesToSubtract) {
 1044  21
             BigMoney money = checkCurrencyEqual(moneyProvider);
 1045  16
             total = total.subtract(money.amount);
 1046  16
         }
 1047  7
         return with(total);
 1048  
     }
 1049  
 
 1050  
     //-----------------------------------------------------------------------
 1051  
     /**
 1052  
      * Returns a copy of this monetary value with the amount subtracted.
 1053  
      * <p>
 1054  
      * This subtracts the specified amount from this monetary amount, returning a new object.
 1055  
      * The amount subtracted must be in the same currency.
 1056  
      * <p>
 1057  
      * No precision is lost in the result.
 1058  
      * The scale of the result will be the maximum of the two scales.
 1059  
      * For example,'USD 25.95' minus 'USD 3.021' gives 'USD 22.929'.
 1060  
      * <p>
 1061  
      * This instance is immutable and unaffected by this method.
 1062  
      * 
 1063  
      * @param moneyToSubtract  the monetary value to subtract, not null
 1064  
      * @return the new instance with the input amount subtracted, never null
 1065  
      * @throws CurrencyMismatchException if the currencies differ
 1066  
      */
 1067  
     public BigMoney minus(BigMoneyProvider moneyToSubtract) {
 1068  17
         BigMoney toSubtract = checkCurrencyEqual(moneyToSubtract);
 1069  10
         return minus(toSubtract.getAmount());
 1070  
     }
 1071  
 
 1072  
     /**
 1073  
      * Returns a copy of this monetary value with the amount subtracted.
 1074  
      * <p>
 1075  
      * This subtracts the specified amount from this monetary amount, returning a new object.
 1076  
      * <p>
 1077  
      * No precision is lost in the result.
 1078  
      * The scale of the result will be the maximum of the two scales.
 1079  
      * For example,'USD 25.95' minus '3.021' gives 'USD 22.929'.
 1080  
      * <p>
 1081  
      * This instance is immutable and unaffected by this method.
 1082  
      * 
 1083  
      * @param amountToSubtract  the monetary value to subtract, not null
 1084  
      * @return the new instance with the input amount subtracted, never null
 1085  
      */
 1086  
     public BigMoney minus(BigDecimal amountToSubtract) {
 1087  15
         MoneyUtils.checkNotNull(amountToSubtract, "Amount must not be null");
 1088  14
         if (amountToSubtract.compareTo(BigDecimal.ZERO) == 0) {
 1089  3
             return this;
 1090  
         }
 1091  11
         BigDecimal newAmount = amount.subtract(amountToSubtract);
 1092  11
         return BigMoney.of(currency, newAmount);
 1093  
     }
 1094  
 
 1095  
     /**
 1096  
      * Returns a copy of this monetary value with the amount subtracted.
 1097  
      * <p>
 1098  
      * This subtracts the specified amount from this monetary amount, returning a new object.
 1099  
      * <p>
 1100  
      * No precision is lost in the result.
 1101  
      * The scale of the result will be the maximum of the two scales.
 1102  
      * For example,'USD 25.95' minus '3.021d' gives 'USD 22.929'.
 1103  
      * <p>
 1104  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 1105  
      * the most expected answer for most programming scenarios.
 1106  
      * Any {@code double} literal in code will be converted to
 1107  
      * exactly the same BigDecimal with the same scale.
 1108  
      * For example, the literal '1.45d' will be converted to '1.45'.
 1109  
      * <p>
 1110  
      * This instance is immutable and unaffected by this method.
 1111  
      * 
 1112  
      * @param amountToSubtract  the monetary value to subtract, not null
 1113  
      * @return the new instance with the input amount subtracted, never null
 1114  
      */
 1115  
     public BigMoney minus(double amountToSubtract) {
 1116  4
         if (amountToSubtract == 0) {
 1117  1
             return this;
 1118  
         }
 1119  3
         BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract));
 1120  3
         return BigMoney.of(currency, newAmount);
 1121  
     }
 1122  
 
 1123  
     /**
 1124  
      * Returns a copy of this monetary value with the amount in major units subtracted.
 1125  
      * <p>
 1126  
      * This subtracts the specified amount in major units from this monetary amount,
 1127  
      * returning a new object. The minor units will be untouched in the result.
 1128  
      * <p>
 1129  
      * No precision is lost in the result.
 1130  
      * The scale of the result will be the maximum of the current scale and 0.
 1131  
      * For example, 'USD 23.45' minus '138' gives 'USD -114.55'.
 1132  
      * <p>
 1133  
      * This instance is immutable and unaffected by this method.
 1134  
      * 
 1135  
      * @param amountToSubtract  the monetary value to subtract, not null
 1136  
      * @return the new instance with the input amount subtracted, never null
 1137  
      */
 1138  
     public BigMoney minusMajor(long amountToSubtract) {
 1139  6
         if (amountToSubtract == 0) {
 1140  2
             return this;
 1141  
         }
 1142  4
         BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract));
 1143  4
         return BigMoney.of(currency, newAmount);
 1144  
     }
 1145  
 
 1146  
     /**
 1147  
      * Returns a copy of this monetary value with the amount in minor units subtracted.
 1148  
      * <p>
 1149  
      * This subtracts the specified amount in minor units from this monetary amount,
 1150  
      * returning a new object.
 1151  
      * <p>
 1152  
      * No precision is lost in the result.
 1153  
      * The scale of the result will be the maximum of the current scale and the default currency scale.
 1154  
      * For example, USD 23.45 minus '138' gives 'USD 22.07'.
 1155  
      * <p>
 1156  
      * This instance is immutable and unaffected by this method.
 1157  
      * 
 1158  
      * @param amountToSubtract  the monetary value to subtract, not null
 1159  
      * @return the new instance with the input amount subtracted, never null
 1160  
      */
 1161  
     public BigMoney minusMinor(long amountToSubtract) {
 1162  7
         if (amountToSubtract == 0) {
 1163  2
             return this;
 1164  
         }
 1165  5
         BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract, currency.getDecimalPlaces()));
 1166  5
         return BigMoney.of(currency, newAmount);
 1167  
     }
 1168  
 
 1169  
     //-----------------------------------------------------------------------
 1170  
     /**
 1171  
      * Returns a copy of this monetary value with the amount in the same currency subtracted
 1172  
      * retaining the scale by rounding the result.
 1173  
      * <p>
 1174  
      * The scale of the result will be the same as the scale of this instance.
 1175  
      * For example,'USD 25.95' minus 'USD 3.029' gives 'USD 22.92 with most rounding modes.
 1176  
      * <p>
 1177  
      * This instance is immutable and unaffected by this method.
 1178  
      * 
 1179  
      * @param moneyToSubtract  the monetary value to add, not null
 1180  
      * @param roundingMode  the rounding mode to use to adjust the scale, not null
 1181  
      * @return the new instance with the input amount subtracted, never null
 1182  
      */
 1183  
     public BigMoney minusRetainScale(BigMoneyProvider moneyToSubtract, RoundingMode roundingMode) {
 1184  7
         BigMoney toSubtract = checkCurrencyEqual(moneyToSubtract);
 1185  6
         return minusRetainScale(toSubtract.getAmount(), roundingMode);
 1186  
     }
 1187  
 
 1188  
     /**
 1189  
      * Returns a copy of this monetary value with the amount subtracted retaining
 1190  
      * the scale by rounding the result.
 1191  
      * <p>
 1192  
      * The scale of the result will be the same as the scale of this instance.
 1193  
      * For example,'USD 25.95' minus '3.029' gives 'USD 22.92' with most rounding modes.
 1194  
      * <p>
 1195  
      * This instance is immutable and unaffected by this method.
 1196  
      * 
 1197  
      * @param amountToSubtract  the monetary value to add, not null
 1198  
      * @param roundingMode  the rounding mode to use to adjust the scale, not null
 1199  
      * @return the new instance with the input amount subtracted, never null
 1200  
      */
 1201  
     public BigMoney minusRetainScale(BigDecimal amountToSubtract, RoundingMode roundingMode) {
 1202  25
         MoneyUtils.checkNotNull(amountToSubtract, "Amount must not be null");
 1203  22
         if (amountToSubtract.compareTo(BigDecimal.ZERO) == 0) {
 1204  4
             return this;
 1205  
         }
 1206  18
         BigDecimal newAmount = amount.subtract(amountToSubtract);
 1207  18
         newAmount = newAmount.setScale(getScale(), roundingMode);
 1208  11
         return BigMoney.of(currency, newAmount);
 1209  
     }
 1210  
 
 1211  
     /**
 1212  
      * Returns a copy of this monetary value with the amount subtracted retaining
 1213  
      * the scale by rounding the result.
 1214  
      * <p>
 1215  
      * The scale of the result will be the same as the scale of this instance.
 1216  
      * For example,'USD 25.95' minus '3.029d' gives 'USD 22.92' with most rounding modes.
 1217  
      * <p>
 1218  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 1219  
      * the most expected answer for most programming scenarios.
 1220  
      * Any {@code double} literal in code will be converted to
 1221  
      * exactly the same BigDecimal with the same scale.
 1222  
      * For example, the literal '1.45d' will be converted to '1.45'.
 1223  
      * <p>
 1224  
      * This instance is immutable and unaffected by this method.
 1225  
      * 
 1226  
      * @param amountToSubtract  the monetary value to add, not null
 1227  
      * @param roundingMode  the rounding mode to use to adjust the scale, not null
 1228  
      * @return the new instance with the input amount subtracted, never null
 1229  
      */
 1230  
     public BigMoney minusRetainScale(double amountToSubtract, RoundingMode roundingMode) {
 1231  16
         if (amountToSubtract == 0) {
 1232  3
             return this;
 1233  
         }
 1234  13
         BigDecimal newAmount = amount.subtract(BigDecimal.valueOf(amountToSubtract));
 1235  13
         newAmount = newAmount.setScale(getScale(), roundingMode);
 1236  8
         return BigMoney.of(currency, newAmount);
 1237  
     }
 1238  
 
 1239  
     //-----------------------------------------------------------------------
 1240  
     /**
 1241  
      * Returns a copy of this monetary value multiplied by the specified value.
 1242  
      * <p>
 1243  
      * No precision is lost in the result.
 1244  
      * The result has a scale equal to the sum of the two scales.
 1245  
      * For example, 'USD 1.13' multiplied by '2.5' gives 'USD 2.825'.
 1246  
      * <p>
 1247  
      * This instance is immutable and unaffected by this method.
 1248  
      * 
 1249  
      * @param valueToMultiplyBy  the scalar value to multiply by, not null
 1250  
      * @return the new multiplied instance, never null
 1251  
      */
 1252  
     public BigMoney multipliedBy(BigDecimal valueToMultiplyBy) {
 1253  4
         MoneyUtils.checkNotNull(valueToMultiplyBy, "Multiplier must not be null");
 1254  3
         if (valueToMultiplyBy.compareTo(BigDecimal.ONE) == 0) {
 1255  1
             return this;
 1256  
         }
 1257  2
         BigDecimal newAmount = amount.multiply(valueToMultiplyBy);
 1258  2
         return BigMoney.of(currency, newAmount);
 1259  
     }
 1260  
 
 1261  
     /**
 1262  
      * Returns a copy of this monetary value multiplied by the specified value.
 1263  
      * <p>
 1264  
      * No precision is lost in the result.
 1265  
      * The result has a scale equal to the sum of the two scales.
 1266  
      * For example, 'USD 1.13' multiplied by '2.5' gives 'USD 2.825'.
 1267  
      * <p>
 1268  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 1269  
      * the most expected answer for most programming scenarios.
 1270  
      * Any {@code double} literal in code will be converted to
 1271  
      * exactly the same BigDecimal with the same scale.
 1272  
      * For example, the literal '1.45d' will be converted to '1.45'.
 1273  
      * <p>
 1274  
      * This instance is immutable and unaffected by this method.
 1275  
      * 
 1276  
      * @param valueToMultiplyBy  the scalar value to multiply by, not null
 1277  
      * @return the new multiplied instance, never null
 1278  
      */
 1279  
     public BigMoney multipliedBy(double valueToMultiplyBy) {
 1280  3
         if (valueToMultiplyBy == 1) {
 1281  1
             return this;
 1282  
         }
 1283  2
         BigDecimal newAmount = amount.multiply(BigDecimal.valueOf(valueToMultiplyBy));
 1284  2
         return BigMoney.of(currency, newAmount);
 1285  
     }
 1286  
 
 1287  
     /**
 1288  
      * Returns a copy of this monetary value multiplied by the specified value.
 1289  
      * <p>
 1290  
      * No precision is lost in the result.
 1291  
      * The result has a scale equal to the scale of this money.
 1292  
      * For example, 'USD 1.13' multiplied by '2' gives 'USD 2.26'.
 1293  
      * <p>
 1294  
      * This instance is immutable and unaffected by this method.
 1295  
      * 
 1296  
      * @param valueToMultiplyBy  the scalar value to multiply by, not null
 1297  
      * @return the new multiplied instance, never null
 1298  
      */
 1299  
     public BigMoney multipliedBy(long valueToMultiplyBy) {
 1300  6
         if (valueToMultiplyBy == 1) {
 1301  2
             return this;
 1302  
         }
 1303  4
         BigDecimal newAmount = amount.multiply(BigDecimal.valueOf(valueToMultiplyBy));
 1304  4
         return BigMoney.of(currency, newAmount);
 1305  
     }
 1306  
 
 1307  
     //-----------------------------------------------------------------------
 1308  
     /**
 1309  
      * Returns a copy of this monetary value multiplied by the specified value
 1310  
      * using the specified rounding mode to adjust the scale of the result.
 1311  
      * <p>
 1312  
      * This multiplies this money by the specified value, retaining the scale of this money.
 1313  
      * This will frequently lose precision, hence the need for a rounding mode.
 1314  
      * For example, 'USD 1.13' multiplied by '2.5' and rounding down gives 'USD 2.82'.
 1315  
      * <p>
 1316  
      * This instance is immutable and unaffected by this method.
 1317  
      * 
 1318  
      * @param valueToMultiplyBy  the scalar value to multiply by, not null
 1319  
      * @param roundingMode  the rounding mode to use to bring the decimal places back in line, not null
 1320  
      * @return the new multiplied instance, never null
 1321  
      * @throws ArithmeticException if the rounding fails
 1322  
      */
 1323  
     public BigMoney multiplyRetainScale(BigDecimal valueToMultiplyBy, RoundingMode roundingMode) {
 1324  22
         MoneyUtils.checkNotNull(valueToMultiplyBy, "Multiplier must not be null");
 1325  20
         MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null");
 1326  16
         if (valueToMultiplyBy.compareTo(BigDecimal.ONE) == 0) {
 1327  4
             return this;
 1328  
         }
 1329  12
         BigDecimal newAmount = amount.multiply(valueToMultiplyBy);
 1330  12
         newAmount = newAmount.setScale(getScale(), roundingMode);
 1331  12
         return BigMoney.of(currency, newAmount);
 1332  
     }
 1333  
 
 1334  
     /**
 1335  
      * Returns a copy of this monetary value multiplied by the specified value
 1336  
      * using the specified rounding mode to adjust the scale of the result.
 1337  
      * <p>
 1338  
      * This multiplies this money by the specified value, retaining the scale of this money.
 1339  
      * This will frequently lose precision, hence the need for a rounding mode.
 1340  
      * For example, 'USD 1.13' multiplied by '2.5' and rounding down gives 'USD 2.82'.
 1341  
      * <p>
 1342  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 1343  
      * the most expected answer for most programming scenarios.
 1344  
      * Any {@code double} literal in code will be converted to
 1345  
      * exactly the same BigDecimal with the same scale.
 1346  
      * For example, the literal '1.45d' will be converted to '1.45'.
 1347  
      * <p>
 1348  
      * This instance is immutable and unaffected by this method.
 1349  
      * 
 1350  
      * @param valueToMultiplyBy  the scalar value to multiply by, not null
 1351  
      * @param roundingMode  the rounding mode to use to bring the decimal places back in line, not null
 1352  
      * @return the new multiplied instance, never null
 1353  
      * @throws ArithmeticException if the rounding fails
 1354  
      */
 1355  
     public BigMoney multiplyRetainScale(double valueToMultiplyBy, RoundingMode roundingMode) {
 1356  10
         return multiplyRetainScale(BigDecimal.valueOf(valueToMultiplyBy), roundingMode);
 1357  
     }
 1358  
 
 1359  
     //-----------------------------------------------------------------------
 1360  
     /**
 1361  
      * Returns a copy of this monetary value divided by the specified value
 1362  
      * using the specified rounding mode to adjust the scale.
 1363  
      * <p>
 1364  
      * The result has the same scale as this instance.
 1365  
      * For example, 'USD 1.13' divided by '2.5' and rounding down gives 'USD 0.45'
 1366  
      * (amount rounded down from 0.452).
 1367  
      * <p>
 1368  
      * This instance is immutable and unaffected by this method.
 1369  
      * 
 1370  
      * @param valueToDivideBy  the scalar value to divide by, not null
 1371  
      * @param roundingMode  the rounding mode to use, not null
 1372  
      * @return the new divided instance, never null
 1373  
      * @throws ArithmeticException if dividing by zero
 1374  
      * @throws ArithmeticException if the rounding fails
 1375  
      */
 1376  
     public BigMoney dividedBy(BigDecimal valueToDivideBy, RoundingMode roundingMode) {
 1377  12
         MoneyUtils.checkNotNull(valueToDivideBy, "Divisor must not be null");
 1378  10
         MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null");
 1379  8
         if (valueToDivideBy.compareTo(BigDecimal.ONE) == 0) {
 1380  2
             return this;
 1381  
         }
 1382  6
         BigDecimal newAmount = amount.divide(valueToDivideBy, roundingMode);
 1383  6
         return BigMoney.of(currency, newAmount);
 1384  
     }
 1385  
 
 1386  
     /**
 1387  
      * Returns a copy of this monetary value divided by the specified value
 1388  
      * using the specified rounding mode to adjust the scale.
 1389  
      * <p>
 1390  
      * The result has the same scale as this instance.
 1391  
      * For example, 'USD 1.13' divided by '2.5' and rounding down gives 'USD 0.45'
 1392  
      * (amount rounded down from 0.452).
 1393  
      * <p>
 1394  
      * The amount is converted via {@link BigDecimal#valueOf(double)} which yields
 1395  
      * the most expected answer for most programming scenarios.
 1396  
      * Any {@code double} literal in code will be converted to
 1397  
      * exactly the same BigDecimal with the same scale.
 1398  
      * For example, the literal '1.45d' will be converted to '1.45'.
 1399  
      * <p>
 1400  
      * This instance is immutable and unaffected by this method.
 1401  
      * 
 1402  
      * @param valueToDivideBy  the scalar value to divide by, not null
 1403  
      * @param roundingMode  the rounding mode to use, not null
 1404  
      * @return the new divided instance, never null
 1405  
      * @throws ArithmeticException if dividing by zero
 1406  
      * @throws ArithmeticException if the rounding fails
 1407  
      */
 1408  
     public BigMoney dividedBy(double valueToDivideBy, RoundingMode roundingMode) {
 1409  10
         MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null");
 1410  8
         if (valueToDivideBy == 1) {
 1411  2
             return this;
 1412  
         }
 1413  6
         BigDecimal newAmount = amount.divide(BigDecimal.valueOf(valueToDivideBy), roundingMode);
 1414  6
         return BigMoney.of(currency, newAmount);
 1415  
     }
 1416  
 
 1417  
     /**
 1418  
      * Returns a copy of this monetary value divided by the specified value
 1419  
      * using the specified rounding mode to adjust the decimal places in the result.
 1420  
      * <p>
 1421  
      * The result has the same scale as this instance.
 1422  
      * For example, 'USD 1.13' divided by '2' and rounding down gives 'USD 0.56'
 1423  
      * (amount rounded down from 0.565).
 1424  
      * <p>
 1425  
      * This instance is immutable and unaffected by this method.
 1426  
      * 
 1427  
      * @param valueToDivideBy  the scalar value to divide by, not null
 1428  
      * @param roundingMode  the rounding mode to use, not null
 1429  
      * @return the new divided instance, never null
 1430  
      * @throws ArithmeticException if dividing by zero
 1431  
      */
 1432  
     public BigMoney dividedBy(long valueToDivideBy, RoundingMode roundingMode) {
 1433  10
         if (valueToDivideBy == 1) {
 1434  2
             return this;
 1435  
         }
 1436  8
         BigDecimal newAmount = amount.divide(BigDecimal.valueOf(valueToDivideBy), roundingMode);
 1437  8
         return BigMoney.of(currency, newAmount);
 1438  
     }
 1439  
 
 1440  
     //-----------------------------------------------------------------------
 1441  
     /**
 1442  
      * Returns a copy of this monetary value with the amount negated.
 1443  
      * <p>
 1444  
      * This instance is immutable and unaffected by this method.
 1445  
      * 
 1446  
      * @return the new instance with the amount negated, never null
 1447  
      */
 1448  
     public BigMoney negated() {
 1449  10
         if (isZero()) {
 1450  1
             return this;
 1451  
         }
 1452  9
         return BigMoney.of(currency, amount.negate());
 1453  
     }
 1454  
 
 1455  
     /**
 1456  
      * Returns a copy of this monetary value with a positive amount.
 1457  
      * <p>
 1458  
      * This instance is immutable and unaffected by this method.
 1459  
      * 
 1460  
      * @return the new instance with the amount converted to be positive, never null
 1461  
      */
 1462  
     public BigMoney abs() {
 1463  2
         return (isNegative() ? negated() : this);
 1464  
     }
 1465  
 
 1466  
     //-----------------------------------------------------------------------
 1467  
     /**
 1468  
      * Returns a copy of this monetary value rounded to the specified scale without
 1469  
      * changing the current scale.
 1470  
      * <p>
 1471  
      * Scale is described in {@link BigDecimal} and represents the point below which
 1472  
      * the monetary value is zero. Negative scales round increasingly large numbers.
 1473  
      * Unlike {@link #withScale(int)}, this scale of the result is unchanged.
 1474  
      * <ul>
 1475  
      * <li>Rounding 'EUR 45.23' to a scale of -1 returns 40.00 or 50.00 depending on the rounding mode.
 1476  
      * <li>Rounding 'EUR 45.23' to a scale of 0 returns 45.00 or 46.00 depending on the rounding mode.
 1477  
      * <li>Rounding 'EUR 45.23' to a scale of 1 returns 45.20 or 45.30 depending on the rounding mode.
 1478  
      * <li>Rounding 'EUR 45.23' to a scale of 2 has no effect (it already has that scale).
 1479  
      * <li>Rounding 'EUR 45.23' to a scale of 3 has no effect (the scale is not increased).
 1480  
      * </ul>
 1481  
      * This instance is immutable and unaffected by this method.
 1482  
      * 
 1483  
      * @param scale  the new scale
 1484  
      * @param roundingMode  the rounding mode to use, not null
 1485  
      * @return the new instance with the amount converted to be positive, never null
 1486  
      * @throws ArithmeticException if the rounding fails
 1487  
      */
 1488  
     public BigMoney rounded(int scale, RoundingMode roundingMode) {
 1489  18
         MoneyUtils.checkNotNull(roundingMode, "RoundingMode must not be null");
 1490  18
         if (scale >= getScale()) {
 1491  6
             return this;
 1492  
         }
 1493  12
         int currentScale = amount.scale();
 1494  12
         BigDecimal newAmount = amount.setScale(scale, roundingMode).setScale(currentScale);
 1495  12
         return BigMoney.of(currency, newAmount);
 1496  
     }
 1497  
 
 1498  
     //-----------------------------------------------------------------------
 1499  
     /**
 1500  
      * Returns a copy of this monetary value converted into another currency
 1501  
      * using the specified conversion rate.
 1502  
      * <p>
 1503  
      * The scale of the result will be the sum of the scale of this money and
 1504  
      * the scale of the multiplier. If desired, the scale of the result can be
 1505  
      * adjusted to the scale of the new currency using {@link #withCurrencyScale()}.
 1506  
      * <p>
 1507  
      * This instance is immutable and unaffected by this method.
 1508  
      * 
 1509  
      * @param currency  the new currency, not null
 1510  
      * @param conversionMultipler  the conversion factor between the currencies, not null
 1511  
      * @return the new multiplied instance, never null
 1512  
      * @throws IllegalArgumentException if the currency is the same as this currency
 1513  
      * @throws IllegalArgumentException if the conversion multiplier is negative
 1514  
      */
 1515  
     public BigMoney convertedTo(CurrencyUnit currency, BigDecimal conversionMultipler) {
 1516  19
         MoneyUtils.checkNotNull(currency, "CurrencyUnit must not be null");
 1517  16
         MoneyUtils.checkNotNull(conversionMultipler, "Multiplier must not be null");
 1518  13
         if (this.currency == currency) {
 1519  3
             throw new IllegalArgumentException("Cannot convert to the same currency");
 1520  
         }
 1521  10
         if (conversionMultipler.compareTo(BigDecimal.ZERO) < 0) {
 1522  3
             throw new IllegalArgumentException("Cannot convert using a negative conversion multiplier");
 1523  
         }
 1524  7
         BigDecimal newAmount = amount.multiply(conversionMultipler);
 1525  7
         return BigMoney.of(currency, newAmount);
 1526  
     }
 1527  
 
 1528  
     /**
 1529  
      * Returns a copy of this monetary value converted into another currency
 1530  
      * using the specified conversion rate, with a rounding mode used to adjust
 1531  
      * the decimal places in the result.
 1532  
      * <p>
 1533  
      * The result will have the same scale as this instance even though it will
 1534  
      * be in a different currency.
 1535  
      * <p>
 1536  
      * This instance is immutable and unaffected by this method.
 1537  
      * 
 1538  
      * @param currency  the new currency, not null
 1539  
      * @param conversionMultipler  the conversion factor between the currencies, not null
 1540  
      * @param roundingMode  the rounding mode to use to bring the decimal places back in line, not null
 1541  
      * @return the new multiplied instance, never null
 1542  
      * @throws IllegalArgumentException if the currency is the same as this currency
 1543  
      * @throws IllegalArgumentException if the conversion multiplier is negative
 1544  
      * @throws ArithmeticException if the rounding fails
 1545  
      */
 1546  
     public BigMoney convertRetainScale(CurrencyUnit currency, BigDecimal conversionMultipler, RoundingMode roundingMode) {
 1547  7
         return convertedTo(currency, conversionMultipler).withScale(getScale(), roundingMode);
 1548  
     }
 1549  
 
 1550  
     //-----------------------------------------------------------------------
 1551  
     /**
 1552  
      * Implements the {@code BigMoneyProvider} interface, trivially
 1553  
      * returning {@code this}.
 1554  
      * 
 1555  
      * @return the money instance, never null
 1556  
      */
 1557  
     public BigMoney toBigMoney() {
 1558  444
         return this;
 1559  
     }
 1560  
 
 1561  
     /**
 1562  
      * Converts this money to an instance of {@code Money} without rounding.
 1563  
      * If the scale of this money exceeds the currency scale an exception will be thrown.
 1564  
      * 
 1565  
      * @return the money instance, never null
 1566  
      * @throws ArithmeticException if the rounding fails
 1567  
      */
 1568  
     public Money toMoney() {
 1569  22
         return Money.of(this);
 1570  
     }
 1571  
 
 1572  
     /**
 1573  
      * Converts this money to an instance of {@code Money}.
 1574  
      * 
 1575  
      * @param roundingMode  the rounding mode to use, not null
 1576  
      * @return the money instance, never null
 1577  
      * @throws ArithmeticException if the rounding fails
 1578  
      */
 1579  
     public Money toMoney(RoundingMode roundingMode) {
 1580  2
         return Money.of(this, roundingMode);
 1581  
     }
 1582  
 
 1583  
     //-----------------------------------------------------------------------
 1584  
     /**
 1585  
      * Checks if this instance and the specified instance have the same currency.
 1586  
      * 
 1587  
      * @param money  the money to check, not null
 1588  
      * @return true if they have the same currency
 1589  
      */
 1590  
     public boolean isSameCurrency(BigMoneyProvider money) {
 1591  164
         return (currency.equals(of(money).getCurrencyUnit()));
 1592  
     }
 1593  
 
 1594  
     //-----------------------------------------------------------------------
 1595  
     /**
 1596  
      * Compares this monetary value to another.
 1597  
      * The compared values must be in the same currency.
 1598  
      * 
 1599  
      * @param other  the other monetary value, not null
 1600  
      * @return -1 if this is less than , 0 if equal, 1 if greater than
 1601  
      * @throws CurrencyMismatchException if the currencies differ
 1602  
      */
 1603  
     public int compareTo(BigMoneyProvider other) {
 1604  100
         BigMoney otherMoney = of(other);
 1605  100
         if (currency.equals(otherMoney.currency) == false) {
 1606  12
             throw new CurrencyMismatchException(getCurrencyUnit(), otherMoney.getCurrencyUnit());
 1607  
         }
 1608  88
         return amount.compareTo(otherMoney.amount);
 1609  
     }
 1610  
 
 1611  
     /**
 1612  
      * Checks if this monetary value is equal to another.
 1613  
      * <p>
 1614  
      * This ignores the scale of the amount.
 1615  
      * Thus, 'USD 30.00' and 'USD 30' are equal.
 1616  
      * <p>
 1617  
      * The compared values must be in the same currency.
 1618  
      * 
 1619  
      * @param other  the other monetary value, not null
 1620  
      * @return true is this is greater than the specified monetary value
 1621  
      * @throws CurrencyMismatchException if the currencies differ
 1622  
      * @see #equals(Object)
 1623  
      */
 1624  
     public boolean isEqual(BigMoneyProvider other) {
 1625  22
         return compareTo(other) == 0;
 1626  
     }
 1627  
 
 1628  
     /**
 1629  
      * Checks if this monetary value is greater than another.
 1630  
      * The compared values must be in the same currency.
 1631  
      * 
 1632  
      * @param other  the other monetary value, not null
 1633  
      * @return true is this is greater than the specified monetary value
 1634  
      * @throws CurrencyMismatchException if the currencies differ
 1635  
      */
 1636  
     public boolean isGreaterThan(BigMoneyProvider other) {
 1637  20
         return compareTo(other) > 0;
 1638  
     }
 1639  
 
 1640  
     /**
 1641  
      * Checks if this monetary value is less than another.
 1642  
      * The compared values must be in the same currency.
 1643  
      * 
 1644  
      * @param other  the other monetary value, not null
 1645  
      * @return true is this is less than the specified monetary value
 1646  
      * @throws CurrencyMismatchException if the currencies differ
 1647  
      */
 1648  
     public boolean isLessThan(BigMoneyProvider other) {
 1649  20
         return compareTo(other) < 0;
 1650  
     }
 1651  
 
 1652  
     //-----------------------------------------------------------------------
 1653  
     /**
 1654  
      * Checks if this monetary value equals another.
 1655  
      * <p>
 1656  
      * Like BigDecimal, this method compares the scale of the amount.
 1657  
      * Thus, 'USD 30.00' and 'USD 30' are not equal.
 1658  
      * <p>
 1659  
      * The compared values must be in the same currency.
 1660  
      * 
 1661  
      * @param other  the other object, null returns false
 1662  
      * @return true if this instance equals the other instance
 1663  
      * @see #isEqual
 1664  
      */
 1665  
     @Override
 1666  
     public boolean equals(Object other) {
 1667  156
         if (this == other) {
 1668  37
             return true;
 1669  
         }
 1670  119
         if (other instanceof BigMoney) {
 1671  116
             BigMoney otherMoney = (BigMoney) other;
 1672  116
             return currency.equals(otherMoney.getCurrencyUnit()) &&
 1673  
                     amount.equals(otherMoney.amount);
 1674  
         }
 1675  3
         return false;
 1676  
     }
 1677  
 
 1678  
     /**
 1679  
      * Returns a hash code for this monetary value.
 1680  
      * 
 1681  
      * @return a suitable hash code
 1682  
      */
 1683  
     @Override
 1684  
     public int hashCode() {
 1685  4
         return currency.hashCode() ^ amount.hashCode();
 1686  
     }
 1687  
 
 1688  
     //-----------------------------------------------------------------------
 1689  
     /**
 1690  
      * Gets this monetary value as a string.
 1691  
      * <p>
 1692  
      * The format is the 3 letter ISO currency code, followed by a space,
 1693  
      * followed by the amount as per {@link BigDecimal#toPlainString()}.
 1694  
      * 
 1695  
      * @return the string representation of this monetary value, never null
 1696  
      */
 1697  
     @Override
 1698  
     @ToString
 1699  
     public String toString() {
 1700  168
         return new StringBuilder()
 1701  
             .append(currency.getCode())
 1702  
             .append(' ')
 1703  
             .append(amount.toPlainString())
 1704  
             .toString();
 1705  
     }
 1706  
 
 1707  
 }