001/* 002 Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. 003 004 Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 use this file except in compliance with the License. You may obtain a copy of 006 the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010 Unless required by applicable law or agreed to in writing, software 011 distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 License for the specific language governing permissions and limitations under 014 the License. 015 */ 016package org.javamoney.moneta; 017 018import java.io.Serializable; 019import java.math.BigDecimal; 020import java.math.MathContext; 021import java.math.RoundingMode; 022import java.util.Objects; 023 024import javax.money.CurrencyUnit; 025import javax.money.Monetary; 026import javax.money.MonetaryAmount; 027import javax.money.MonetaryAmountFactory; 028import javax.money.MonetaryContext; 029import javax.money.MonetaryException; 030import javax.money.MonetaryOperator; 031import javax.money.MonetaryQuery; 032import javax.money.NumberValue; 033import javax.money.UnknownCurrencyException; 034import javax.money.format.MonetaryAmountFormat; 035 036import org.javamoney.moneta.ToStringMonetaryAmountFormat.ToStringMonetaryAmountFormatStyle; 037import org.javamoney.moneta.spi.MoneyAmountFactory; 038import org.javamoney.moneta.spi.DefaultNumberValue; 039import org.javamoney.moneta.spi.MoneyUtils; 040 041/** 042 * Default immutable implementation of {@link MonetaryAmount} based 043 * on {@link BigDecimal} as numeric representation. 044 * 045 * As required by {@link MonetaryAmount} this class is final, thread-safe, 046 * immutable and serializable. 047 * 048 * This class can be configured with an arbitrary {@link MonetaryContext}. The 049 * default {@link MonetaryContext} used models by default the same settings as 050 * {@link MathContext#DECIMAL64} . This default {@link MonetaryContext} can also 051 * be reconfigured by adding a file {@code /javamoney.properties} to the 052 * classpath, with the following content: 053 * 054 * <pre> 055 * # Default MathContext for Money 056 * #------------------------------- 057 * # Custom MonetaryContext, overrides default entries from 058 * # org.javamoney.moneta.Money.monetaryContext 059 * # RoundingMode hereby is optional (default = HALF_EVEN) 060 * org.javamoney.moneta.Money.defaults.precision=256 061 * org.javamoney.moneta.Money.defaults.roundingMode=HALF_EVEN 062 * </pre> 063 * 064 * @author Anatole Tresch 065 * @author Werner Keil 066 * @version 0.7 067 */ 068public final class Money implements MonetaryAmount, Comparable<MonetaryAmount>, Serializable { 069 070 /** 071 * serialVersionUID. 072 */ 073 private static final long serialVersionUID = -7565813772046251748L; 074 075 /** 076 * The default {@link MonetaryContext} applied, if not set explicitly on 077 * creation. 078 */ 079 public static final MonetaryContext DEFAULT_MONETARY_CONTEXT = new DefaultMonetaryContextFactory().getContext(); 080 081 /** 082 * The currency of this amount. 083 */ 084 private final CurrencyUnit currency; 085 086 /** 087 * the {@link MonetaryContext} used by this instance, e.g. on division. 088 */ 089 private final MonetaryContext monetaryContext; 090 091 /** 092 * The numeric part of this amount. 093 */ 094 private final BigDecimal number; 095 096 /** 097 * Creates a new instance os {@link Money}. 098 * 099 * @param currency the currency, not null. 100 * @param number the amount, not null. 101 * @throws ArithmeticException If the number exceeds the capabilities of the default 102 * {@link MonetaryContext}. 103 */ 104 private Money(BigDecimal number, CurrencyUnit currency) { 105 this(number, currency, null); 106 } 107 108 /** 109 * Creates a new instance of {@link Money}. 110 * 111 * @param currency the currency, not {@code null}. 112 * @param number the amount, not {@code null}. 113 * @param monetaryContext the {@link MonetaryContext}, if {@code null}, the default is 114 * used. 115 * @throws ArithmeticException If the number exceeds the capabilities of the 116 * {@link MonetaryContext} used. 117 */ 118 private Money(BigDecimal number, CurrencyUnit currency, MonetaryContext monetaryContext) { 119 Objects.requireNonNull(currency, "Currency is required."); 120 this.currency = currency; 121 if (monetaryContext!=null) { 122 this.monetaryContext = monetaryContext; 123 } else { 124 this.monetaryContext = DEFAULT_MONETARY_CONTEXT; 125 } 126 Objects.requireNonNull(number, "Number is required."); 127 this.number = MoneyUtils.getBigDecimal(number, monetaryContext); 128 } 129 130 /** 131 * Returns the amount’s currency, modelled as {@link CurrencyUnit}. 132 * Implementations may co-variantly change the return type to a more 133 * specific implementation of {@link CurrencyUnit} if desired. 134 * 135 * @return the currency, never {@code null} 136 * @see javax.money.MonetaryAmount#getCurrency() 137 */ 138 @Override 139 public CurrencyUnit getCurrency() { 140 return currency; 141 } 142 143 /** 144 * Access the {@link MonetaryContext} used by this instance. 145 * 146 * @return the {@link MonetaryContext} used, never null. 147 * @see javax.money.MonetaryAmount#getContext() 148 */ 149 @Override 150 public MonetaryContext getContext() { 151 return monetaryContext; 152 } 153 154 /** 155 * Gets the number representation of the numeric value of this item. 156 * 157 * @return The {@link Number} representation matching best. 158 */ 159 @Override 160 public NumberValue getNumber() { 161 return new DefaultNumberValue(number); 162 } 163 164 /** 165 * Method that returns BigDecimal.ZERO, if {@link #isZero()}, and 166 * {@link #number #stripTrailingZeros()} in all other cases. 167 * 168 * @return the stripped number value. 169 */ 170 public BigDecimal getNumberStripped() { 171 if (isZero()) { 172 return BigDecimal.ZERO; 173 } 174 return this.number.stripTrailingZeros(); 175 } 176 177 /* 178 * @see java.lang.Comparable#compareTo(java.lang.Object) 179 */ 180 @Override 181 public int compareTo(MonetaryAmount o) { 182 Objects.requireNonNull(o); 183 int compare = getCurrency().getCurrencyCode().compareTo(o.getCurrency().getCurrencyCode()); 184 if (compare == 0) { 185 compare = this.number.compareTo(Money.from(o).number); 186 } 187 return compare; 188 } 189 190 // Arithmetic Operations 191 192 /* 193 * (non-Javadoc) 194 * 195 * @see MonetaryAmount#abs() 196 */ 197 @Override 198 public Money abs() { 199 if (this.isPositiveOrZero()) { 200 return this; 201 } 202 return negate(); 203 } 204 205 /* 206 * (non-Javadoc) 207 * 208 * @see MonetaryAmount#divide(MonetaryAmount) 209 */ 210 @Override 211 public Money divide(long divisor) { 212 if (divisor == 1L) { 213 return this; 214 } 215 return divide(BigDecimal.valueOf(divisor)); 216 } 217 218 /* 219 * (non-Javadoc) 220 * 221 * @see MonetaryAmount#divide(MonetaryAmount) 222 */ 223 @Override 224 public Money divide(double divisor) { 225 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 226 return Money.of(0, getCurrency()); 227 } 228 if (divisor == 1.0) { 229 return this; 230 } 231 return divide(new BigDecimal(String.valueOf(divisor))); 232 } 233 234 /* 235 * (non-Javadoc) 236 * 237 * @see 238 * MonetaryAmount#divideAndRemainder(MonetaryAmount) 239 */ 240 @Override 241 public Money[] divideAndRemainder(long divisor) { 242 return divideAndRemainder(BigDecimal.valueOf(divisor)); 243 } 244 245 /* 246 * (non-Javadoc) 247 * 248 * @see 249 * MonetaryAmount#divideAndRemainder(MonetaryAmount) 250 */ 251 @Override 252 public Money[] divideAndRemainder(double divisor) { 253 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 254 Money zero = Money.of(0, getCurrency()); 255 return new Money[]{zero, zero}; 256 } 257 return divideAndRemainder(new BigDecimal(String.valueOf(divisor))); 258 } 259 260 /* 261 * (non-Javadoc) 262 * 263 * @see MonetaryAmount#multiply(Number) 264 */ 265 @Override 266 public Money multiply(long multiplicand) { 267 if (multiplicand == 1L) { 268 return this; 269 } 270 return multiply(BigDecimal.valueOf(multiplicand)); 271 } 272 273 /* 274 * (non-Javadoc) 275 * 276 * @see MonetaryAmount#multiply(Number) 277 */ 278 @Override 279 public Money multiply(double multiplicand) { 280 NumberVerifier.checkNoInfinityOrNaN(multiplicand); 281 if (multiplicand == 1.0d) { 282 return this; 283 } 284 return multiply(new BigDecimal(String.valueOf(multiplicand))); 285 } 286 287 /* 288 * (non-Javadoc) 289 * 290 * @see MonetaryAmount#remainder(Number) 291 */ 292 @Override 293 public Money remainder(long divisor) { 294 return remainder(BigDecimal.valueOf(divisor)); 295 } 296 297 /* 298 * (non-Javadoc) 299 * 300 * @see MonetaryAmount#remainder(Number) 301 */ 302 @Override 303 public Money remainder(double divisor) { 304 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 305 return Money.of(0, getCurrency()); 306 } 307 return remainder(new BigDecimal(String.valueOf(divisor))); 308 } 309 310 /* 311 * (non-Javadoc) 312 * 313 * @see javax.money.MonetaryAmount#isZero() 314 */ 315 @Override 316 public boolean isZero() { 317 return signum() == 0; 318 } 319 320 /* 321 * (non-Javadoc) 322 * 323 * @see javax.money.MonetaryAmount#isPositive() 324 */ 325 @Override 326 public boolean isPositive() { 327 return signum() == 1; 328 } 329 330 /* 331 * (non-Javadoc) 332 * 333 * @see javax.money.MonetaryAmount#isPositiveOrZero() 334 */ 335 @Override 336 public boolean isPositiveOrZero() { 337 return signum() >= 0; 338 } 339 340 /* 341 * (non-Javadoc) 342 * 343 * @see javax.money.MonetaryAmount#isNegative() 344 */ 345 @Override 346 public boolean isNegative() { 347 return signum() == -1; 348 } 349 350 /* 351 * (non-Javadoc) 352 * 353 * @see javax.money.MonetaryAmount#isNegativeOrZero() 354 */ 355 @Override 356 public boolean isNegativeOrZero() { 357 return signum() <= 0; 358 } 359 360 361 /* 362 * }(non-Javadoc) 363 * 364 * @see javax.money.MonetaryAmount#query(javax.money.MonetaryQuery) 365 */ 366 @Override 367 public <R> R query(MonetaryQuery<R> query) { 368 Objects.requireNonNull(query); 369 try { 370 return query.queryFrom(this); 371 } catch (MonetaryException e) { 372 throw e; 373 } catch (Exception e) { 374 throw new MonetaryException("Query failed: " + query, e); 375 } 376 } 377 378 /* 379 * (non-Javadoc) 380 * 381 * @see javax.money.MonetaryAmount#with(javax.money.MonetaryOperator) 382 */ 383 @Override 384 public Money with(MonetaryOperator operator) { 385 Objects.requireNonNull(operator); 386 try { 387 return Money.class.cast(operator.apply(this)); 388 } catch (MonetaryException e) { 389 throw e; 390 } catch (Exception e) { 391 throw new MonetaryException("Operator failed: " + operator, e); 392 } 393 } 394 395 /* 396 * (non-Javadoc) 397 * 398 * @see javax.money.MonetaryAmount#add(javax.money.MonetaryAmount) 399 */ 400 @Override 401 public Money add(MonetaryAmount amount) { 402 MoneyUtils.checkAmountParameter(amount, this.currency); 403 if (amount.isZero()) { 404 return this; 405 } 406 return new Money(this.number.add(amount.getNumber().numberValue(BigDecimal.class)), getCurrency()); 407 } 408 409 /* 410 * (non-Javadoc) 411 * 412 * @see javax.money.MonetaryAmount#divide(java.lang.Number) 413 */ 414 @Override 415 public Money divide(Number divisor) { 416 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 417 return Money.of(0, getCurrency()); 418 } 419 BigDecimal divisorBD = MoneyUtils.getBigDecimal(divisor); 420 if (divisorBD.equals(BigDecimal.ONE)) { 421 return this; 422 } 423 BigDecimal dec = 424 this.number.divide(divisorBD, MoneyUtils.getMathContext(getContext(), RoundingMode.HALF_EVEN)); 425 return new Money(dec, getCurrency()); 426 } 427 428 @Override 429 public Money[] divideAndRemainder(Number divisor) { 430 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 431 Money zero = Money.of(0, getCurrency()); 432 return new Money[]{zero, zero}; 433 } 434 BigDecimal divisorBD = MoneyUtils.getBigDecimal(divisor); 435 if (divisorBD.equals(BigDecimal.ONE)) { 436 return new Money[]{this, new Money(BigDecimal.ZERO, getCurrency())}; 437 } 438 BigDecimal[] dec = this.number.divideAndRemainder(divisorBD); 439 return new Money[]{new Money(dec[0], getCurrency()), new Money(dec[1], getCurrency())}; 440 } 441 442 /* 443 * (non-Javadoc) 444 * 445 * @see 446 * org.javamoney.moneta.AbstractMoney#divideToIntegralValue(java.lang.Number 447 * ) 448 */ 449 @Override 450 public Money divideToIntegralValue(long divisor) { 451 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 452 } 453 454 @Override 455 public Money divideToIntegralValue(double divisor) { 456 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 457 return Money.of(0, getCurrency()); 458 } 459 return divideToIntegralValue(MoneyUtils.getBigDecimal(divisor)); 460 } 461 462 @Override 463 public Money divideToIntegralValue(Number divisor) { 464 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 465 return Money.of(0, getCurrency()); 466 } 467 BigDecimal divisorBD = MoneyUtils.getBigDecimal(divisor); 468 BigDecimal dec = this.number.divideToIntegralValue(divisorBD); 469 return new Money(dec, getCurrency()); 470 } 471 472 /* 473 * (non-Javadoc) 474 * 475 * @see org.javamoney.moneta.AbstractMoney#multiply(java.lang.Number) 476 */ 477 @Override 478 public Money multiply(Number multiplicand) { 479 NumberVerifier.checkNoInfinityOrNaN(multiplicand); 480 BigDecimal multiplicandBD = MoneyUtils.getBigDecimal(multiplicand); 481 if (multiplicandBD.equals(BigDecimal.ONE)) { 482 return this; 483 } 484 BigDecimal dec = this.number.multiply(multiplicandBD); 485 return new Money(dec, getCurrency()); 486 } 487 488 /* 489 * (non-Javadoc) 490 * 491 * @see javax.money.MonetaryAmount#negate() 492 */ 493 @Override 494 public Money negate() { 495 return new Money(this.number.negate(), getCurrency()); 496 } 497 498 /* 499 * (non-Javadoc) 500 * 501 * @see javax.money.MonetaryAmount#plus() 502 */ 503 @Override 504 public Money plus() { 505 return this; 506 } 507 508 /* 509 * (non-Javadoc) 510 * 511 * @see javax.money.MonetaryAmount#subtract(javax.money.MonetaryAmount) 512 */ 513 @Override 514 public Money subtract(MonetaryAmount subtrahend) { 515 MoneyUtils.checkAmountParameter(subtrahend, this.currency); 516 if (subtrahend.isZero()) { 517 return this; 518 } 519 return new Money(this.number.subtract(subtrahend.getNumber().numberValue(BigDecimal.class)), getCurrency()); 520 } 521 522 /* 523 * (non-Javadoc) 524 * 525 * @see javax.money.MonetaryAmount#stripTrailingZeros() 526 */ 527 @Override 528 public Money stripTrailingZeros() { 529 if (isZero()) { 530 return new Money(BigDecimal.ZERO, getCurrency()); 531 } 532 return new Money(this.number.stripTrailingZeros(), getCurrency()); 533 } 534 535 /* 536 * (non-Javadoc) 537 * 538 * @see org.javamoney.moneta.AbstractMoney#remainder(java.math.BigDecimal) 539 */ 540 @Override 541 public Money remainder(Number divisor) { 542 if (NumberVerifier.isInfinityAndNotNaN(divisor)) { 543 return new Money(BigDecimal.ZERO, getCurrency()); 544 } 545 BigDecimal bd = MoneyUtils.getBigDecimal(divisor); 546 return new Money(this.number.remainder(bd), getCurrency()); 547 } 548 549 /* 550 * (non-Javadoc) 551 * 552 * @see javax.money.MonetaryAmount#scaleByPowerOfTen(int) 553 */ 554 @Override 555 public Money scaleByPowerOfTen(int power) { 556 return new Money(this.number.scaleByPowerOfTen(power), getCurrency()); 557 } 558 559 /* 560 * (non-Javadoc) 561 * 562 * @see javax.money.MonetaryAmount#signum() 563 */ 564 @Override 565 public int signum() { 566 return this.number.signum(); 567 } 568 569 /* 570 * (non-Javadoc) 571 * 572 * @see javax.money.MonetaryAmount#isLessThan(javax.money.MonetaryAmount) 573 */ 574 @Override 575 public boolean isLessThan(MonetaryAmount amount) { 576 MoneyUtils.checkAmountParameter(amount, this.currency); 577 return number.stripTrailingZeros() 578 .compareTo(amount.getNumber().numberValue(BigDecimal.class).stripTrailingZeros()) < 0; 579 } 580 581 /* 582 * (non-Javadoc) 583 * 584 * @see 585 * javax.money.MonetaryAmount#isLessThanOrEqualTo(javax.money.MonetaryAmount 586 * ) 587 */ 588 @Override 589 public boolean isLessThanOrEqualTo(MonetaryAmount amount) { 590 MoneyUtils.checkAmountParameter(amount, this.currency); 591 return number.stripTrailingZeros() 592 .compareTo(amount.getNumber().numberValue(BigDecimal.class).stripTrailingZeros()) <= 0; 593 } 594 595 /* 596 * (non-Javadoc) 597 * 598 * @see javax.money.MonetaryAmount#isGreaterThan(javax.money.MonetaryAmount) 599 */ 600 @Override 601 public boolean isGreaterThan(MonetaryAmount amount) { 602 MoneyUtils.checkAmountParameter(amount, this.currency); 603 return number.stripTrailingZeros() 604 .compareTo(amount.getNumber().numberValue(BigDecimal.class).stripTrailingZeros()) > 0; 605 } 606 607 /* 608 * (non-Javadoc) 609 * 610 * @see 611 * javax.money.MonetaryAmount#isGreaterThanOrEqualTo(javax.money.MonetaryAmount 612 * ) #see 613 */ 614 @Override 615 public boolean isGreaterThanOrEqualTo(MonetaryAmount amount) { 616 MoneyUtils.checkAmountParameter(amount, this.currency); 617 return number.stripTrailingZeros() 618 .compareTo(amount.getNumber().numberValue(BigDecimal.class).stripTrailingZeros()) >= 0; 619 } 620 621 /* 622 * (non-Javadoc) 623 * 624 * @see javax.money.MonetaryAmount#isEqualTo(javax.money.MonetaryAmount) 625 */ 626 @Override 627 public boolean isEqualTo(MonetaryAmount amount) { 628 MoneyUtils.checkAmountParameter(amount, this.currency); 629 return number.stripTrailingZeros() 630 .compareTo(amount.getNumber().numberValue(BigDecimal.class).stripTrailingZeros()) == 0; 631 } 632 633 /* 634 * (non-Javadoc) 635 * 636 * @see javax.money.MonetaryAmount#getFactory() 637 */ 638 @Override 639 public MonetaryAmountFactory<Money> getFactory() { 640 return new MoneyAmountFactory().setAmount(this); 641 } 642 643 /* 644 * (non-Javadoc) 645 * 646 * @see java.lang.Object#equals(java.lang.Object) 647 */ 648 @Override 649 public boolean equals(Object obj) { 650 if (obj == this) { 651 return true; 652 } 653 if (obj instanceof Money) { 654 Money other = (Money) obj; 655 return Objects.equals(getCurrency(), other.getCurrency()) && 656 Objects.equals(getNumberStripped(), other.getNumberStripped()); 657 } 658 return false; 659 } 660 661 /* 662 * (non-Javadoc) 663 * 664 * @see java.lang.Object#toString() 665 */ 666 @Override 667 public String toString() { 668 return getCurrency().getCurrencyCode() + ' ' + number.toPlainString(); 669 } 670 671 /* 672 * (non-Javadoc) 673 * 674 * @see java.lang.Object#hashCode() 675 */ 676 @Override 677 public int hashCode() { 678 return Objects.hash(getCurrency(), getNumberStripped()); 679 } 680 681 /** 682 * Creates a new instance of {@link Money}, using the default 683 * {@link MonetaryContext}. 684 * 685 * @param number numeric value, not {@code null}. 686 * @param currency currency unit, not {@code null}. 687 * @return a {@code Money} combining the numeric value and currency unit. 688 * @throws ArithmeticException If the number exceeds the capabilities of the default 689 * {@link MonetaryContext} used. 690 */ 691 public static Money of(BigDecimal number, CurrencyUnit currency) { 692 return new Money(number, currency); 693 } 694 695 /** 696 * Creates a new instance of {@link Money}, using an explicit 697 * {@link MonetaryContext}. 698 * 699 * @param number numeric value, not {@code null}. 700 * @param currency currency unit, not {@code null}. 701 * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the 702 * default {@link MonetaryContext} is used. 703 * @return a {@code Money} instance based on the monetary context with the 704 * given numeric value, currency unit. 705 * @throws ArithmeticException If the number exceeds the capabilities of the 706 * {@link MonetaryContext} used. 707 */ 708 public static Money of(BigDecimal number, CurrencyUnit currency, MonetaryContext monetaryContext) { 709 return new Money(number, currency, monetaryContext); 710 } 711 712 /** 713 * Creates a new instance of {@link Money}, using the default 714 * {@link MonetaryContext}. 715 * 716 * @param currency The target currency, not null. 717 * @param number The numeric part, not null. 718 * @return A new instance of {@link Money}. 719 * @throws ArithmeticException If the number exceeds the capabilities of the default 720 * {@link MonetaryContext} used. 721 */ 722 public static Money of(Number number, CurrencyUnit currency) { 723 return new Money(MoneyUtils.getBigDecimal(number), currency); 724 } 725 726 /** 727 * Creates a new instance of {@link Money}, using an explicit 728 * {@link MonetaryContext}. 729 * 730 * @param currency The target currency, not null. 731 * @param number The numeric part, not null. 732 * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the 733 * default {@link MonetaryContext} is used. 734 * @return A new instance of {@link Money}. 735 * @throws ArithmeticException If the number exceeds the capabilities of the 736 * {@link MonetaryContext} used. 737 */ 738 public static Money of(Number number, CurrencyUnit currency, MonetaryContext monetaryContext) { 739 return new Money(MoneyUtils.getBigDecimal(number), currency, monetaryContext); 740 } 741 742 /** 743 * Static factory method for creating a new instance of {@link Money}. 744 * 745 * @param currencyCode The target currency as ISO currency code. 746 * @param number The numeric part, not null. 747 * @return A new instance of {@link Money}. 748 */ 749 public static Money of(Number number, String currencyCode) { 750 return new Money(MoneyUtils.getBigDecimal(number), Monetary.getCurrency(currencyCode)); 751 } 752 753 /** 754 * Static factory method for creating a new instance of {@link Money}. 755 * 756 * @param currencyCode The target currency as ISO currency code. 757 * @param number The numeric part, not null. 758 * @return A new instance of {@link Money}. 759 */ 760 public static Money of(BigDecimal number, String currencyCode) { 761 return new Money(number, Monetary.getCurrency(currencyCode)); 762 } 763 764 /** 765 * Static factory method for creating a new instance of {@link Money}. 766 * 767 * @param currencyCode The target currency as ISO currency code. 768 * @param number The numeric part, not null. 769 * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the 770 * default {@link MonetaryContext} is used. 771 * @return A new instance of {@link Money}. 772 */ 773 public static Money of(Number number, String currencyCode, MonetaryContext monetaryContext) { 774 return new Money(MoneyUtils.getBigDecimal(number), Monetary.getCurrency(currencyCode), 775 monetaryContext); 776 } 777 778 /** 779 * Static factory method for creating a new instance of {@link Money}. 780 * 781 * @param currencyCode The target currency as ISO currency code. 782 * @param number The numeric part, not null. 783 * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the 784 * default {@link MonetaryContext} is used. 785 * @return A new instance of {@link Money}. 786 */ 787 public static Money of(BigDecimal number, String currencyCode, MonetaryContext monetaryContext) { 788 return new Money(number, Monetary.getCurrency(currencyCode), monetaryContext); 789 } 790 791 /** 792 * Obtains an instance of {@link Money} representing zero. 793 * @param currency the currency, not null. 794 * @return an instance of {@link Money} representing zero. 795 * @since 1.0.1 796 */ 797 public static Money zero(CurrencyUnit currency) { 798 return new Money(BigDecimal.ZERO, currency); 799 } 800 801 /** 802 * Obtains an instance of {@code Money} from an amount in minor units. 803 * For example, {@code ofMinor(USD, 1234)} creates the instance {@code USD 12.34}. 804 * @param currency the currency 805 * @param amountMinor the amount of money in the minor division of the currency 806 * @return the Money from minor units 807 * @throws NullPointerException when the currency is null 808 * @throws IllegalArgumentException when {@link CurrencyUnit#getDefaultFractionDigits()} is lesser than zero. 809 * @see CurrencyUnit#getDefaultFractionDigits() 810 * @since 1.0.1 811 */ 812 public static Money ofMinor(CurrencyUnit currency, long amountMinor) { 813 return ofMinor(currency, amountMinor, currency.getDefaultFractionDigits()); 814 } 815 816 /** 817 * Obtains an instance of {@code Money} from an amount in minor units. 818 * For example, {@code ofMinor(USD, 1234, 2)} creates the instance {@code USD 12.34}. 819 * @param currency the currency, not null 820 * @param amountMinor the amount of money in the minor division of the currency 821 * @param factionDigits number of digits 822 * @return the monetary amount from minor units 823 * @see CurrencyUnit#getDefaultFractionDigits() 824 * @see Money#ofMinor(CurrencyUnit, long, int) 825 * @throws NullPointerException when the currency is null 826 * @throws IllegalArgumentException when the factionDigits is negative 827 * @since 1.0.1 828 */ 829 public static Money ofMinor(CurrencyUnit currency, long amountMinor, int factionDigits) { 830 if(factionDigits < 0) { 831 throw new IllegalArgumentException("The factionDigits cannot be negative"); 832 } 833 return of(BigDecimal.valueOf(amountMinor, factionDigits), currency); 834 } 835 836 /** 837 * Converts (if necessary) the given {@link MonetaryAmount} to a 838 * {@link Money} instance. The {@link MonetaryContext} will be adapted as 839 * necessary, if the precision of the given amount exceeds the capabilities 840 * of the default {@link MonetaryContext}. 841 * 842 * @param amt the amount to be converted 843 * @return an according Money instance. 844 */ 845 public static Money from(MonetaryAmount amt) { 846 if (amt.getClass() == Money.class) { 847 return (Money) amt; 848 } 849 return Money.of(amt.getNumber().numberValue(BigDecimal.class), amt.getCurrency(), amt.getContext()); 850 } 851 852 /** 853 * Obtains an instance of Money from a text string such as 'EUR 25.25'. 854 * 855 * @param text the text to parse, not null 856 * @return Money instance 857 * @throws NumberFormatException if the amount is not parseable. 858 * @throws UnknownCurrencyException if the currency is not resolvable. 859 */ 860 public static Money parse(CharSequence text) { 861 return parse(text, DEFAULT_FORMATTER); 862 } 863 864 /** 865 * Obtains an instance of Money from a text using specific formatter. 866 * 867 * @param text the text to parse not null 868 * @param formatter the formatter to use not null 869 * @return Money instance 870 */ 871 public static Money parse(CharSequence text, MonetaryAmountFormat formatter) { 872 return from(formatter.parse(text)); 873 } 874 875 private static final ToStringMonetaryAmountFormat DEFAULT_FORMATTER = ToStringMonetaryAmountFormat 876 .of(ToStringMonetaryAmountFormatStyle.MONEY); 877 878 /** 879 * Just to don't break the compatibility. 880 * Don't use it 881 * @param number the number, not null. 882 * @deprecated Will be removed. 883 */ 884 @Deprecated 885 public static boolean isInfinityAndNotNaN(Number number) { 886 if (Double.class == number.getClass() || Float.class == number.getClass()) { 887 double dValue = number.doubleValue(); 888 if (!Double.isNaN(dValue) && Double.isInfinite(dValue)) { 889 return true; 890 } 891 } 892 return false; 893 } 894 895 896 /** 897 * Just to don't break the compatibility. 898 * Don't use it 899 * @param number the number, not null. 900 * @deprecated Will be removed. 901 */ 902 @Deprecated 903 public static void checkNoInfinityOrNaN(Number number) { 904 if (Double.class == number.getClass() || Float.class == number.getClass()) { 905 double dValue = number.doubleValue(); 906 if (Double.isNaN(dValue)) { 907 throw new ArithmeticException("Not a valid input: NaN."); 908 } else if (Double.isInfinite(dValue)) { 909 throw new ArithmeticException("Not a valid input: INFINITY: " + dValue); 910 } 911 } 912 } 913 914}