001/* 002 * Copyright (c) 2012, 2013, Credit Suisse (Anatole Tresch), Werner Keil. 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.IOException; 019import java.io.ObjectInputStream; 020import java.io.ObjectOutputStream; 021import java.io.ObjectStreamException; 022import java.io.Serializable; 023import java.math.BigDecimal; 024import java.math.BigInteger; 025import java.math.MathContext; 026import java.math.RoundingMode; 027import java.util.concurrent.atomic.AtomicLong; 028 029import javax.money.CurrencyUnit; 030import javax.money.MonetaryAdjuster; 031import javax.money.MonetaryAmount; 032import javax.money.MonetaryQuery; 033 034/** 035 * Platform RI: Default immutable implementation of {@link MonetaryAmount} based 036 * on {@link BigDecimal} for the numeric representation. 037 * <p> 038 * As required by {@link MonetaryAmount} this class is final, thread-safe, 039 * immutable and serializable. 040 * 041 * @version 0.6.1 042 * @author Anatole Tresch 043 * @author Werner Keil 044 */ 045public final class Money implements MonetaryAmount, Comparable<MonetaryAmount>, 046 Serializable { 047 048 /** 049 * 050 */ 051 private static final long serialVersionUID = -7565813772046251748L; 052 053 public static final MathContext DEFAULT_MATH_CONTEXT = initDefaultMathContext(); 054 055 private static final int[] DENOM_ARRAY = new int[] { 1, 10, 100, 1000, 056 10000, 100000, 1000000 }; 057 058 /** The numeric part of this amount. */ 059 private BigDecimal number; 060 061 /** The currency of this amount. */ 062 private CurrencyUnit currency; 063 064 /** tHE DEFAULT {@link MathContext} used by this instance, e.g. on division. */ 065 private MathContext mathContext; 066 067 /** 068 * Creates a new instance os {@link Money}. 069 * 070 * @param currency 071 * the currency, not null. 072 * @param number 073 * the amount, not null. 074 */ 075 private Money(CurrencyUnit currency, Number number) { 076 this(currency, number, DEFAULT_MATH_CONTEXT); 077 } 078 079 private static MathContext initDefaultMathContext() { 080 // TODO Initialize default, e.g. by system properties, or better: 081 // classpath properties! 082 return MathContext.DECIMAL64; 083 } 084 085 /** 086 * Creates a new instance os {@link Money}. 087 * 088 * @param currency 089 * the currency, not null. 090 * @param number 091 * the amount, not null. 092 */ 093 private Money(CurrencyUnit currency, Number number, MathContext mathContext) { 094 if (currency == null) { 095 throw new IllegalArgumentException("Currency is required."); 096 } 097 if (number == null) { 098 throw new IllegalArgumentException("Number is required."); 099 } 100 if (mathContext == null) { 101 throw new IllegalArgumentException("MathContext is required."); 102 } 103 checkNumber(number); 104 this.currency = currency; 105 this.mathContext = mathContext; 106 this.number = getBigDecimal(number, mathContext); 107 } 108 109 // Static Factory Methods 110 /** 111 * Translates a {@code BigDecimal} value and a {@code CurrencyUnit} currency 112 * into a {@code Money}. 113 * 114 * @param number 115 * numeric value of the {@code Money}. 116 * @param currency 117 * currency unit of the {@code Money}. 118 * @return a {@code Money} combining the numeric value and currency unit. 119 */ 120 public static Money of(CurrencyUnit currency, BigDecimal number) { 121 return new Money(currency, number, DEFAULT_MATH_CONTEXT); 122 } 123 124 /** 125 * Translates a {@code BigDecimal} value and a {@code CurrencyUnit} currency 126 * into a {@code Money}. 127 * 128 * @param number 129 * numeric value of the {@code Money}. 130 * @param currency 131 * currency unit of the {@code Money}. 132 * @param mathContext 133 * the {@link MathContext} to be used. 134 * @return a {@code Money} combining the numeric value and currency unit. 135 */ 136 public static Money of(CurrencyUnit currency, BigDecimal number, 137 MathContext mathContext) { 138 return new Money(currency, number, mathContext); 139 } 140 141 /** 142 * Static factory method for creating a new instance of {@link Money}. 143 * 144 * @param currency 145 * The target currency, not null. 146 * @param number 147 * The numeric part, not null. 148 * @return A new instance of {@link Money}. 149 */ 150 public static Money of(CurrencyUnit currency, Number number) { 151 return new Money(currency, number, DEFAULT_MATH_CONTEXT); 152 } 153 154 /** 155 * Static factory method for creating a new instance of {@link Money}. 156 * 157 * @param currency 158 * The target currency, not null. 159 * @param number 160 * The numeric part, not null. 161 * @return A new instance of {@link Money}. 162 */ 163 public static Money of(CurrencyUnit currency, Number number, 164 MathContext mathContext) { 165 return new Money(currency, number, mathContext); 166 } 167 168 /** 169 * Static factory method for creating a new instance of {@link Money}. 170 * 171 * @param isoCurrencyCode 172 * The target currency as ISO currency code. 173 * @param number 174 * The numeric part, not null. 175 * @return A new instance of {@link Money}. 176 */ 177 public static Money of(String currencyCode, Number number) { 178 return new Money(MoneyCurrency.of(currencyCode), number, 179 DEFAULT_MATH_CONTEXT); 180 } 181 182 /** 183 * Static factory method for creating a new instance of {@link Money}. 184 * 185 * @param isoCurrencyCode 186 * The target currency as ISO currency code. 187 * @param number 188 * The numeric part, not null. 189 * @return A new instance of {@link Money}. 190 */ 191 public static Money of(String currencyCode, Number number, 192 MathContext mathContext) { 193 return new Money(MoneyCurrency.of(currencyCode), number, mathContext); 194 } 195 196/** 197 * Factory method creating a zero instance with the given {@code currency); 198 * @param currency the target currency of the amount being created. 199 * @return 200 */ 201 public static Money ofZero(CurrencyUnit currency) { 202 return new Money(currency, BigDecimal.ZERO, DEFAULT_MATH_CONTEXT); 203 } 204 205/** 206 * Factory method creating a zero instance with the given {@code currency); 207 * @param currency the target currency of the amount being created. 208 * @return 209 */ 210 public static Money ofZero(String currency) { 211 return ofZero(MoneyCurrency.of(currency)); 212 } 213 214 /* 215 * (non-Javadoc) 216 * 217 * @see java.lang.Object#hashCode() 218 */ 219 @Override 220 public int hashCode() { 221 final int prime = 31; 222 int result = 1; 223 result = prime * result 224 + ((currency == null) ? 0 : currency.hashCode()); 225 result = prime * result + ((number == null) ? 0 : number.hashCode()); 226 return result; 227 } 228 229 /* 230 * (non-Javadoc) 231 * 232 * @see java.lang.Object#equals(java.lang.Object) 233 */ 234 @Override 235 public boolean equals(Object obj) { 236 if (this == obj) 237 return true; 238 if (obj == null) 239 return false; 240 if (getClass() != obj.getClass()) 241 return false; 242 Money other = (Money) obj; 243 if (currency == null) { 244 if (other.currency != null) 245 return false; 246 } else if (!currency.equals(other.currency)) 247 return false; 248 if (number == null) { 249 if (other.number != null) 250 return false; 251 } else if (!number.equals(other.number)) 252 return false; 253 return true; 254 } 255 256 /* 257 * @see java.lang.Comparable#compareTo(java.lang.Object) 258 */ 259 public int compareTo(MonetaryAmount o) { 260 checkAmountParameter(o); 261 int compare = -1; 262 if (this.currency.equals(o.getCurrency())) { 263 compare = this.number.compareTo(Money.from(o).number); 264 } else { 265 compare = this.currency.getCurrencyCode().compareTo( 266 o.getCurrency().getCurrencyCode()); 267 } 268 return compare; 269 } 270 271 /* 272 * (non-Javadoc) 273 * 274 * @see javax.money.MonetaryAmount#getCurrency() 275 */ 276 public CurrencyUnit getCurrency() { 277 return currency; 278 } 279 280 /** 281 * Access the {@link MathContext} used by this instance. 282 * 283 * @return the {@link MathContext} used, never null. 284 */ 285 public MathContext getMathContext() { 286 return this.mathContext; 287 } 288 289 /** 290 * Allows to change the {@link MathContext}. The context will used, on 291 * subsequent operation, where feasible and also propagated to child results 292 * of arithmetic calculations. 293 * 294 * @param mathContext 295 * The new {@link MathContext}, not null. 296 * @return a new {@link Money} instance, with the new {@link MathContext}. 297 */ 298 public Money withMathContext(MathContext mathContext) { 299 if (mathContext == null) { 300 throw new IllegalArgumentException("MathContext required."); 301 } 302 return new Money(this.currency, this.number, mathContext); 303 } 304 305 /* 306 * (non-Javadoc) 307 * 308 * @see javax.money.MonetaryAmount#abs() 309 */ 310 public Money abs() { 311 if (this.isPositiveOrZero()) { 312 return this; 313 } 314 return this.negate(); 315 } 316 317 // Arithmetic Operations 318 319 /* 320 * (non-Javadoc) 321 * 322 * @see javax.money.MonetaryAmount#add(javax.money.MonetaryAmount) 323 */ 324 public Money add(MonetaryAmount amount) { 325 checkAmountParameter(amount); 326 return new Money(this.currency, this.number.add( 327 Money.from(amount).number, this.mathContext), 328 this.mathContext); 329 } 330 331 private BigDecimal getBigDecimal(Number num) { 332 if (num instanceof BigDecimal) { 333 return (BigDecimal) num; 334 } 335 if (num instanceof Long || num instanceof Integer) { 336 return BigDecimal.valueOf(num.longValue()); 337 } 338 if (num instanceof Float || num instanceof Double) { 339 return new BigDecimal(num.toString()); 340 } 341 if (num instanceof Byte || num instanceof AtomicLong) { 342 return BigDecimal.valueOf(num.longValue()); 343 } 344 try { 345 // Avoid imprecise conversion to double value if at all possible 346 return new BigDecimal(num.toString()); 347 } catch (NumberFormatException e) { 348 } 349 return BigDecimal.valueOf(num.doubleValue()); 350 } 351 352 private BigDecimal getBigDecimal(Number number, MathContext mathContext) { 353 if (number instanceof BigDecimal) { 354 return (BigDecimal) number; 355 } else { 356 return new BigDecimal(number.doubleValue(), mathContext); 357 } 358 } 359 360 /* 361 * (non-Javadoc) 362 * 363 * @see javax.money.MonetaryAmount#divide(javax.money.MonetaryAmount) 364 */ 365 public Money divide(MonetaryAmount divisor) { 366 checkAmountParameter(divisor); 367 BigDecimal dec = this.number.divide(Money.from(divisor).number, 368 this.mathContext); 369 return new Money(this.currency, dec, this.mathContext); 370 } 371 372 /* 373 * (non-Javadoc) 374 * 375 * @see javax.money.MonetaryAmount#divide(javax.money.MonetaryAmount) 376 */ 377 public Money divide(Number divisor) { 378 BigDecimal dec = this.number.divide(getBigDecimal(divisor), 379 this.mathContext); 380 return new Money(this.currency, dec, this.mathContext); 381 } 382 383 /* 384 * (non-Javadoc) 385 * 386 * @see 387 * javax.money.MonetaryAmount#divideAndRemainder(javax.money.MonetaryAmount) 388 */ 389 public Money[] divideAndRemainder(MonetaryAmount divisor) { 390 checkAmountParameter(divisor); 391 BigDecimal[] dec = this.number.divideAndRemainder( 392 Money.from(divisor).number, this.mathContext); 393 return new Money[] { 394 new Money(this.currency, dec[0], this.mathContext), 395 new Money(this.currency, dec[1], this.mathContext) }; 396 } 397 398 /* 399 * (non-Javadoc) 400 * 401 * @see 402 * javax.money.MonetaryAmount#divideAndRemainder(javax.money.MonetaryAmount) 403 */ 404 public Money[] divideAndRemainder(Number divisor) { 405 BigDecimal[] dec = this.number.divideAndRemainder( 406 getBigDecimal(divisor), this.mathContext); 407 return new Money[] { 408 new Money(this.currency, dec[0], this.mathContext), 409 new Money(this.currency, dec[1], this.mathContext) }; 410 } 411 412 /* 413 * (non-Javadoc) 414 * 415 * @see 416 * javax.money.MonetaryAmount#divideToIntegralValue(javax.money.MonetaryAmount 417 * ) 418 */ 419 public Money divideToIntegralValue(MonetaryAmount divisor) { 420 checkAmountParameter(divisor); 421 BigDecimal dec = this.number.divideToIntegralValue( 422 Money.from(divisor).number, this.mathContext); 423 return new Money(this.currency, dec, this.mathContext); 424 } 425 426 /* 427 * (non-Javadoc) 428 * 429 * @see javax.money.MonetaryAmount#divideToIntegralValue(Number) )D 430 */ 431 public Money divideToIntegralValue(Number divisor) { 432 BigDecimal dec = this.number.divideToIntegralValue( 433 getBigDecimal(divisor), this.mathContext); 434 return new Money(this.currency, dec, this.mathContext); 435 } 436 437 /* 438 * (non-Javadoc) 439 * 440 * @see javax.money.MonetaryAmount#multiply(javax.money.MonetaryAmount) 441 */ 442 public Money multiply(MonetaryAmount multiplicand) { 443 checkAmountParameter(multiplicand); 444 BigDecimal dec = this.number.multiply( 445 Money.from(multiplicand).number, this.mathContext); 446 return new Money(this.currency, dec, this.mathContext); 447 } 448 449 /* 450 * (non-Javadoc) 451 * 452 * @see javax.money.MonetaryAmount#multiply(Number) 453 */ 454 public Money multiply(Number multiplicand) { 455 BigDecimal dec = this.number.multiply(getBigDecimal(multiplicand), 456 this.mathContext); 457 return new Money(this.currency, dec, this.mathContext); 458 } 459 460 /* 461 * (non-Javadoc) 462 * 463 * @see javax.money.MonetaryAmount#negate() 464 */ 465 public Money negate() { 466 return new Money(this.currency, this.number.negate(this.mathContext), 467 this.mathContext); 468 } 469 470 /* 471 * (non-Javadoc) 472 * 473 * @see javax.money.MonetaryAmount#plus() 474 */ 475 public Money plus() { 476 return new Money(this.currency, this.number.plus(this.mathContext), 477 this.mathContext); 478 } 479 480 /* 481 * (non-Javadoc) 482 * 483 * @see javax.money.MonetaryAmount#subtract(javax.money.MonetaryAmount) 484 */ 485 public Money subtract(MonetaryAmount subtrahend) { 486 checkAmountParameter(subtrahend); 487 return new Money(this.currency, this.number.subtract( 488 Money.from(subtrahend).number, this.mathContext), 489 this.mathContext); 490 } 491 492 /* 493 * (non-Javadoc) 494 * 495 * @see javax.money.MonetaryAmount#pow(int) 496 */ 497 public Money pow(int n) { 498 return new Money(this.currency, this.number.pow(n, this.mathContext), 499 this.mathContext); 500 } 501 502 /* 503 * (non-Javadoc) 504 * 505 * @see javax.money.MonetaryAmount#ulp() 506 */ 507 public Money ulp() { 508 return new Money(this.currency, this.number.ulp()); 509 } 510 511 /* 512 * (non-Javadoc) 513 * 514 * @see javax.money.MonetaryAmount#remainder(javax.money.MonetaryAmount) 515 */ 516 public Money remainder(MonetaryAmount divisor) { 517 checkAmountParameter(divisor); 518 return new Money(this.currency, this.number.remainder( 519 Money.from(divisor).number, this.mathContext), 520 this.mathContext); 521 } 522 523 /* 524 * (non-Javadoc) 525 * 526 * @see javax.money.MonetaryAmount#remainder(Number) 527 */ 528 public Money remainder(Number divisor) { 529 return new Money(this.currency, this.number.remainder( 530 getBigDecimal(divisor), this.mathContext), 531 this.mathContext); 532 } 533 534 /* 535 * (non-Javadoc) 536 * 537 * @see javax.money.MonetaryAmount#scaleByPowerOfTen(int) 538 */ 539 public Money scaleByPowerOfTen(int n) { 540 return new Money(this.currency, this.number.scaleByPowerOfTen(n), 541 this.mathContext); 542 } 543 544 /* 545 * (non-Javadoc) 546 * 547 * @see javax.money.MonetaryAmount#isZero() 548 */ 549 public boolean isZero() { 550 return this.number.signum() == 0; 551 } 552 553 /* 554 * (non-Javadoc) 555 * 556 * @see javax.money.MonetaryAmount#isPositive() 557 */ 558 public boolean isPositive() { 559 return signum() == 1; 560 } 561 562 /* 563 * (non-Javadoc) 564 * 565 * @see javax.money.MonetaryAmount#isPositiveOrZero() 566 */ 567 public boolean isPositiveOrZero() { 568 return signum() >= 0; 569 } 570 571 /* 572 * (non-Javadoc) 573 * 574 * @see javax.money.MonetaryAmount#isNegative() 575 */ 576 public boolean isNegative() { 577 return signum() == -1; 578 } 579 580 /* 581 * (non-Javadoc) 582 * 583 * @see javax.money.MonetaryAmount#isNegativeOrZero() 584 */ 585 public boolean isNegativeOrZero() { 586 return signum() <= 0; 587 } 588 589 /* 590 * (non-Javadoc) 591 * 592 * @see javax.money.MonetaryAmount#with(java.lang.Number) 593 */ 594 public Money with(Number amount) { 595 checkNumber(amount); 596 return new Money(this.currency, getBigDecimal(amount), this.mathContext); 597 } 598 599 /** 600 * Creates a new Money instance, hereby changing the {@link MathContext} to 601 * be used. This allows to adapt the {@link MathContext}, when required. 602 * 603 * @param context 604 * the {@link MathContext} to be replaced, not {@code null} 605 * @return the new amount with the same numeric value and 606 * {@link CurrencyUnit}, but the new {@link MathContext}. 607 */ 608 public Money with(MathContext context) { 609 if (context == null) { 610 throw new IllegalArgumentException("MathContext required"); 611 } 612 return new Money(currency, this.number, context); 613 } 614 615 /** 616 * Creates a new Money instance, by just replacing the {@link CurrencyUnit} 617 * and the numeric amount. 618 * 619 * @param currency 620 * the currency unit to be replaced, not {@code null} 621 * @return the new amount with the same numeric value and 622 * {@link MathContext}, but the new {@link CurrencyUnit}. 623 */ 624 public Money with(CurrencyUnit currency, Number amount) { 625 checkNumber(amount); 626 return new Money(currency, getBigDecimal(amount), this.mathContext); 627 } 628 629 /** 630 * Creates a new Money instance, by just replacing the {@link CurrencyUnit}. 631 * 632 * @param currency 633 * the currency unit to be replaced, not {@code null} 634 * @return the new amount with the same numeric value and 635 * {@link MathContext}, but the new {@link CurrencyUnit}. 636 */ 637 public Money with(CurrencyUnit currency) { 638 if (currency == null) { 639 throw new IllegalArgumentException("currency required"); 640 } 641 return new Money(currency, this.number, this.mathContext); 642 } 643 644 /* 645 * (non-Javadoc) 646 * 647 * @see javax.money.MonetaryAmount#getScale() 648 */ 649 public int getScale() { 650 return this.number.scale(); 651 } 652 653 /* 654 * (non-Javadoc) 655 * 656 * @see javax.money.MonetaryAmount#getPrecision() 657 */ 658 public int getPrecision() { 659 return this.number.precision(); 660 } 661 662 /* 663 * (non-Javadoc) 664 * 665 * @see javax.money.MonetaryAmount#longValue() 666 */ 667 public long longValue() { 668 return this.number.longValue(); 669 } 670 671 /* 672 * (non-Javadoc) 673 * 674 * @see javax.money.MonetaryAmount#longValueExact() 675 */ 676 public long longValueExact() { 677 return this.number.longValueExact(); 678 } 679 680 /* 681 * (non-Javadoc) 682 * 683 * @see javax.money.MonetaryAmount#doubleValue() 684 */ 685 public double doubleValue() { 686 return this.number.doubleValue(); 687 } 688 689 /* 690 * (non-Javadoc) 691 * 692 * @see javax.money.MonetaryAmount#signum() 693 */ 694 695 public int signum() { 696 return this.number.signum(); 697 } 698 699 /* 700 * (non-Javadoc) 701 * 702 * @see javax.money.MonetaryAmount#toEngineeringString() 703 */ 704 public String toEngineeringString() { 705 return this.currency.getCurrencyCode() + ' ' 706 + this.number.toEngineeringString(); 707 } 708 709 /* 710 * (non-Javadoc) 711 * 712 * @see javax.money.MonetaryAmount#toPlainString() 713 */ 714 public String toPlainString() { 715 return this.currency.getCurrencyCode() + ' ' 716 + this.number.toPlainString(); 717 } 718 719 /* 720 * (non-Javadoc) 721 * 722 * @see javax.money.MonetaryAmount#lessThan(javax.money.MonetaryAmount) 723 */ 724 public boolean isLessThan(MonetaryAmount amount) { 725 checkAmountParameter(amount); 726 return number.compareTo(Money.from(amount).number) < 0; 727 } 728 729 /* 730 * (non-Javadoc) 731 * 732 * @see 733 * javax.money.MonetaryAmount#lessThanOrEqualTo(javax.money.MonetaryAmount) 734 */ 735 public boolean isLessThanOrEqualTo(MonetaryAmount amount) { 736 checkAmountParameter(amount); 737 return number.compareTo(Money.from(amount).number) <= 0; 738 } 739 740 /* 741 * (non-Javadoc) 742 * 743 * @see javax.money.MonetaryAmount#greaterThan(javax.money.MonetaryAmount) 744 */ 745 public boolean isGreaterThan(MonetaryAmount amount) { 746 checkAmountParameter(amount); 747 return number.compareTo(Money.from(amount).number) > 0; 748 } 749 750 /* 751 * (non-Javadoc) 752 * 753 * @see 754 * javax.money.MonetaryAmount#greaterThanOrEqualTo(javax.money.MonetaryAmount 755 * ) #see 756 */ 757 public boolean isGreaterThanOrEqualTo(MonetaryAmount amount) { 758 checkAmountParameter(amount); 759 return number.compareTo(Money.from(amount).number) >= 0; 760 } 761 762 /* 763 * (non-Javadoc) 764 * 765 * @see javax.money.MonetaryAmount#isEqualTo(javax.money.MonetaryAmount) 766 */ 767 public boolean isEqualTo(MonetaryAmount amount) { 768 checkAmountParameter(amount); 769 return number.compareTo(Money.from(amount).number) == 0; 770 } 771 772 /* 773 * (non-Javadoc) 774 * 775 * @see javax.money.MonetaryAmount#isNotEqualTo(javax.money.MonetaryAmount) 776 */ 777 public boolean isNotEqualTo(MonetaryAmount amount) { 778 checkAmountParameter(amount); 779 return number.compareTo(Money.from(amount).number) != 0; 780 } 781 782 /* 783 * (non-Javadoc) 784 * 785 * @see javax.money.MonetaryAmount#getNumberType() 786 */ 787 public Class<?> getNumberType() { 788 return BigDecimal.class; 789 } 790 791 /* 792 * }(non-Javadoc) 793 * 794 * @see javax.money.MonetaryAmount#query(javax.money.MonetaryQuery) 795 */ 796 @Override 797 public <T> T query(MonetaryQuery<T> query) { 798 return query.queryFrom(this); 799 } 800 801 /* 802 * @see javax.money.MonetaryAmount#asType(java.lang.Class) 803 */ 804 @SuppressWarnings("unchecked") 805 public <T> T asType(Class<T> type) { 806 if (BigDecimal.class.equals(type)) { 807 return (T) this.number; 808 } 809 if (Number.class.equals(type)) { 810 final T asType = (T) this.number; 811 return asType; 812 } 813 if (Double.class.equals(type)) { 814 return (T) Double.valueOf(this.number.doubleValue()); 815 } 816 if (Float.class.equals(type)) { 817 return (T) Float.valueOf(this.number.floatValue()); 818 } 819 if (Long.class.equals(type)) { 820 return (T) Long.valueOf(this.number.longValue()); 821 } 822 if (Integer.class.equals(type)) { 823 return (T) Integer.valueOf(this.number.intValue()); 824 } 825 if (Short.class.equals(type)) { 826 return (T) Short.valueOf(this.number.shortValue()); 827 } 828 if (Byte.class.equals(type)) { 829 return (T) Byte.valueOf(this.number.byteValue()); 830 } 831 if (BigInteger.class.equals(type)) { 832 return (T) this.number.toBigInteger(); 833 } 834 throw new IllegalArgumentException("Unsupported representation type: " 835 + type); 836 } 837 838 /** 839 * Gets the number representation of the numeric value of this item. 840 * 841 * @return The {@link Number} represention matching best. 842 */ 843 public Number asNumber() { 844 return this.number; 845 } 846 847 private void writeObject(ObjectOutputStream oos) throws IOException { 848 oos.writeObject(this.number); 849 oos.writeObject(this.currency); 850 oos.writeObject(this.mathContext); 851 } 852 853 private void readObject(ObjectInputStream ois) throws IOException, 854 ClassNotFoundException { 855 this.number = (BigDecimal) ois.readObject(); 856 this.currency = (CurrencyUnit) ois.readObject(); 857 this.mathContext = (MathContext) ois.readObject(); 858 } 859 860 private void readObjectNoData() 861 throws ObjectStreamException { 862 if (this.number == null) { 863 this.number = BigDecimal.ZERO; 864 } 865 if (this.currency == null) { 866 this.currency = MoneyCurrency.of( 867 "XXX"); // no currency 868 } 869 if (this.mathContext == null) { 870 this.mathContext = DEFAULT_MATH_CONTEXT; 871 } 872 } 873 874 /* 875 * (non-Javadoc) 876 * 877 * @see java.lang.Object#toString() 878 */ 879 @Override 880 public String toString() { 881 return currency.getCurrencyCode() + ' ' + number.toString(); 882 } 883 884 /* 885 * (non-Javadoc) 886 * 887 * @see javax.money.MonetaryAmount#getAmountWhole() 888 */ 889 @Override 890 public long getAmountWhole() { 891 return this.number.setScale(0, 892 RoundingMode.DOWN).longValueExact(); 893 } 894 895 /* 896 * (non-Javadoc) 897 * 898 * @see javax.money.MonetaryAmount#getAmountFractionNumerator() 899 */ 900 @Override 901 public long getAmountFractionNumerator() { 902 BigDecimal bd = this.number.remainder(BigDecimal.ONE); 903 return bd.movePointRight(getScale()).longValueExact(); 904 } 905 906 /* 907 * (non-Javadoc) 908 * 909 * @see javax.money.MonetaryAmount#getAmountFractionDenominator() 910 */ 911 @Override 912 public long getAmountFractionDenominator() { 913 return BigDecimal.valueOf(10).pow(getScale()).longValueExact(); 914 } 915 916 @Override 917 public Money with(MonetaryAdjuster adjuster) { 918 MonetaryAmount amt = adjuster.adjustInto(this); 919 return Money.from(amt); 920 } 921 922 public static Money from(MonetaryAmount amt) { 923 if (amt.getClass() == Money.class) { 924 return (Money) amt; 925 } 926 if (amt.getClass() == FastMoney.class) { 927 return Money.of(amt.getCurrency(), ((FastMoney) amt).asNumber(), 928 DEFAULT_MATH_CONTEXT); 929 } 930 return Money.of(amt.getCurrency(), asNumber(amt), 931 DEFAULT_MATH_CONTEXT); 932 } 933 934 public static BigDecimal asNumber(MonetaryAmount amt) { 935 long denom = amt.getAmountFractionDenominator(); 936 for (int i = 0; i < DENOM_ARRAY.length; i++) { 937 if (denom == DENOM_ARRAY[i]) { 938 try { 939 long total = amt.getAmountWhole() * denom; 940 total = total + amt.getAmountFractionNumerator(); 941 return BigDecimal.valueOf(total, i); 942 } catch (ArithmeticException ex) { 943 // go ahead, using slow conversion 944 } 945 } 946 } 947 // slow creation follows here 948 BigDecimal whole = BigDecimal.valueOf(amt.getAmountWhole()); 949 BigDecimal fraction = BigDecimal.valueOf(amt 950 .getAmountFractionNumerator()); 951 return whole.add(fraction); 952 } 953 954 /** 955 * Platform RI: This is an inner checker class for aspects of 956 * {@link MonetaryAmount}. It may be used by multiple implementations 957 * (inside the same package) to avoid code duplication. 958 * 959 * This class is for internal use only. 960 * 961 * @author Werner Keil 962 */ 963 static final class Checker { 964 private Checker() { 965 } 966 967 /** 968 * Internal method to check for correct number parameter. 969 * 970 * @param number 971 * @throws IllegalArgumentException 972 * If the number is null 973 */ 974 static final void checkNumber(Number number) { 975 if (number == null) { 976 throw new IllegalArgumentException("Number is required."); 977 } 978 } 979 980 /** 981 * Method to check if a currency is compatible with this amount 982 * instance. 983 * 984 * @param amount 985 * The monetary amount to be compared to, never null. 986 * @throws IllegalArgumentException 987 * If the amount is null, or the amount's currency is not 988 * compatible (same {@link CurrencyUnit#getNamespace()} and 989 * same {@link CurrencyUnit#getCurrencyCode()}). 990 */ 991 static final void checkAmountParameter(CurrencyUnit currency, 992 MonetaryAmount amount) { 993 if (amount == null) { 994 throw new IllegalArgumentException("Amount must not be null."); 995 } 996 final CurrencyUnit amountCurrency = amount.getCurrency(); 997 if (!(currency.getCurrencyCode().equals(amountCurrency 998 .getCurrencyCode()))) { 999 throw new CurrencyMismatchException(currency, amountCurrency); 1000 } 1001 } 1002 } 1003 1004 /** 1005 * Method to check if a currency is compatible with this amount instance. 1006 * 1007 * @param amount 1008 * The monetary amount to be compared to, never null. 1009 * @throws IllegalArgumentException 1010 * If the amount is null, or the amount's currency is not 1011 * compatible (same {@link CurrencyUnit#getNamespace()} and same 1012 * {@link CurrencyUnit#getCurrencyCode()}). 1013 */ 1014 private void checkAmountParameter(MonetaryAmount amount) { 1015 if (amount == null) { 1016 throw new IllegalArgumentException("Amount must not be null."); 1017 } 1018 final CurrencyUnit amountCurrency = amount.getCurrency(); 1019 if (!(this.currency 1020 .getCurrencyCode().equals(amountCurrency.getCurrencyCode()))) { 1021 throw new IllegalArgumentException("Currency mismatch: " 1022 + this.currency + '/' + amountCurrency); 1023 } 1024 } 1025 1026 /** 1027 * Internal method to check for correct number parameter. 1028 * 1029 * @param number 1030 * @throws IllegalArgumentException 1031 * If the number is null 1032 */ 1033 private void checkNumber(Number number) { 1034 if (number == null) { 1035 throw new IllegalArgumentException("Number is required."); 1036 } 1037 } 1038 1039}