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 * 016 * Contributors: Anatole Tresch - initial implementation Werner Keil - 017 * extensions and adaptions. 018 */ 019package org.javamoney.moneta; 020 021import java.io.Serializable; 022import java.math.BigDecimal; 023import java.math.BigInteger; 024 025import javax.money.CurrencyUnit; 026import javax.money.MonetaryAdjuster; 027import javax.money.MonetaryAmount; 028import javax.money.MonetaryQuery; 029 030/** 031 * <type>long</type> based implementation of {@link MonetaryAmount}. This class 032 * internally uses a single long number as numeric reporesentation, which 033 * basically is interpreted as minor units.<br/> 034 * It suggested to have a performance advantage of a 10-15 times faster compared 035 * to {@link Money}, which interally uses {@link BigDecimal}. Nevertheless this 036 * comes with a price of less precision. As an example performing the following 037 * calulcation one milltion times, results in slightly different results: 038 * 039 * <pre> 040 * Money money1 = money1.add(Money.of(EURO, 1234567.3444)); 041 * money1 = money1.subtract(Money.of(EURO, 232323)); 042 * money1 = money1.multiply(3.4); 043 * money1 = money1.divide(5.456); 044 * </pre> 045 * 046 * Executed one million (1000000) times this results in 047 * {@code EUR 1657407.962529182}, calculated in 3680 ms, or roughly 3ns/loop. 048 * <p> 049 * whrereas 050 * 051 * <pre> 052 * FastMoney money1 = money1.add(FastMoney.of(EURO, 1234567.3444)); 053 * money1 = money1.subtract(FastMoney.of(EURO, 232323)); 054 * money1 = money1.multiply(3.4); 055 * money1 = money1.divide(5.456); 056 * </pre> 057 * 058 * executed one million (1000000) times results in {@code EUR 1657407.96251}, 059 * calculated in 179 ms, which is less than 1ns/loop. 060 * <p> 061 * Also note than mixxing up types my drastically change the performance 062 * behaviour. E.g. replacing the code above with the following: * 063 * 064 * <pre> 065 * FastMoney money1 = money1.add(Money.of(EURO, 1234567.3444)); 066 * money1 = money1.subtract(FastMoney.of(EURO, 232323)); 067 * money1 = money1.multiply(3.4); 068 * money1 = money1.divide(5.456); 069 * </pre> 070 * 071 * executed one million (1000000) times may execute significantly longer, since 072 * monetary amount type conversion is involved. 073 * 074 * @version 0.5 075 * @author Anatole Tresch 076 * @author Werner Keil 077 */ 078public final class FastMoney implements MonetaryAmount, 079 Comparable<FastMoney>, Serializable { 080 081 private static final long serialVersionUID = 1L; 082 083 /** The numeric part of this amount. */ 084 private final long number; 085 086 /** The current scale represented by the number. */ 087 private static final int SCALE = 5; 088 089 private static final long SCALING_DENOMINATOR = 100000L; 090 091 /** The currency of this amount. */ 092 private final CurrencyUnit currency; 093 094 /** 095 * Creates a new instance os {@link FastMoney}. 096 * 097 * @param currency 098 * the currency, not null. 099 * @param number 100 * the amount, not null. 101 */ 102 private FastMoney(CurrencyUnit currency, Number number) { 103 if (currency == null) { 104 throw new IllegalArgumentException("Currency is required."); 105 } 106 if (number == null) { 107 throw new IllegalArgumentException("Number is required."); 108 } 109 checkNumber(number); 110 this.currency = currency; 111 this.number = getInternalNumber(number); 112 } 113 114 private long getInternalNumber(Number number) { 115 // long whole = number.longValue(); 116 // double fractions = number.doubleValue() % 1; 117 // return (whole * SCALING_DENOMINATOR) 118 // + ((long) (fractions * SCALING_DENOMINATOR)); 119 BigDecimal bd = getBigDecimal(number); 120 return bd.movePointRight(SCALE).longValue(); 121 } 122 123 private static long getInternalNumber(MonetaryAmount amount) { 124 BigDecimal bd = Money.asNumber(amount); 125 return bd.movePointRight(SCALE).longValue(); 126 // 127 // long fractionNumerator = amount.getAmountFractionNumerator(); 128 // long divisor = amount.getAmountFractionDenominator() 129 // * 10 / SCALING_DENOMINATOR; 130 // 131 // // Variant BD: slow! 132 // // BigDecimal fraction = 133 // BigDecimal.valueOf(fractionNumerator).divide( 134 // // BigDecimal.valueOf(divisor)); 135 // // return (amount.getAmountWhole() * SCALING_DENOMINATOR) + 136 // fraction.longValue(); 137 // 138 // // Variant double 139 // double fraction = ((double) fractionNumerator) / divisor; 140 // return (amount.getAmountWhole() * SCALING_DENOMINATOR) + 141 // (long)fraction; 142 // 143 // // Variant number: fastest! 144 // // return (long)(amount.asNumber().doubleValue() * 145 // SCALING_DENOMINATOR); 146 } 147 148 private static double getInternalDouble(MonetaryAmount amount) { 149 if (amount.getClass() == Money.class) { 150 return ((Money) amount).asNumber().doubleValue(); 151 } 152 153 long fractionNumerator = amount.getAmountFractionNumerator(); 154 long divisor = amount.getAmountFractionDenominator() / SCALING_DENOMINATOR; 155 156 double fraction = ((double) fractionNumerator) / divisor / SCALING_DENOMINATOR; 157 return amount.getAmountWhole() + 158 fraction; 159 } 160 161 // private static double getDoubleValue(MonetaryAmount amount) { 162 // long fraction = amount.getAmountFractionNumerator(); 163 // double divisor = ((double) amount.getAmountFractionDenominator()) 164 // / SCALING_DENOMINATOR; 165 // double fractionNum = (long) (fraction / divisor); 166 // return ((double) amount.getAmountWhole()) 167 // + (fractionNum / SCALING_DENOMINATOR); 168 // } 169 170 private FastMoney(CurrencyUnit currency, long number) { 171 if (currency == null) { 172 throw new IllegalArgumentException("Currency is required."); 173 } 174 this.currency = currency; 175 this.number = number; 176 } 177 178 private BigDecimal getBigDecimal(Number num) { 179 if (num instanceof BigDecimal) { 180 return (BigDecimal) num; 181 } 182 if (num instanceof Long || num instanceof Integer 183 || num instanceof Byte) { 184 return BigDecimal.valueOf(num.longValue()); 185 } 186 if (num instanceof Float || num instanceof Double) { 187 return new BigDecimal(num.toString()); 188 } 189 try { 190 // Avoid imprecise conversion to double value if at all possible 191 return new BigDecimal(num.toString()); 192 } catch (NumberFormatException e) { 193 } 194 return BigDecimal.valueOf(num.doubleValue()); 195 } 196 197 /** 198 * Static factory method for creating a new instance of {@link FastMoney}. 199 * 200 * @param currency 201 * The target currency, not null. 202 * @param number 203 * The numeric part, not null. 204 * @return A new instance of {@link FastMoney}. 205 */ 206 public static FastMoney of(CurrencyUnit currency, Number number) { 207 // TODO caching 208 return new FastMoney(currency, number); 209 } 210 211 /** 212 * Static factory method for creating a new instance of {@link FastMoney}. 213 * 214 * @param currencyCode 215 * The target currency as currency code. 216 * @param number 217 * The numeric part, not null. 218 * @return A new instance of {@link FastMoney}. 219 */ 220 public static FastMoney of(String currencyCode, Number number) { 221 return new FastMoney(MoneyCurrency.of(currencyCode), number); 222 } 223 224/** 225 * Facory method creating a zero instance with the given {@code currency); 226 * @param currency the target currency of the amount being created. 227 * @return 228 */ 229 public static MonetaryAmount zero(CurrencyUnit currency) { 230 return new FastMoney(currency, 0L); 231 } 232 233 /** 234 * Get the number represnetation type, E.g. {@code java.math.BigDecimal}. 235 * 236 * @return 237 */ 238 public static Class<?> getNumberClass() { 239 return Long.class; 240 } 241 242 /* 243 * @see java.lang.Comparable#compareTo(java.lang.Object) 244 */ 245 public int compareTo(FastMoney o) { 246 int compare = -1; 247 if (this.currency.equals(o.getCurrency())) { 248 if (this.number < o.number) { 249 compare = 0; 250 } else if (this.number < o.number) { 251 compare = -1; 252 } else { 253 compare = 1; 254 } 255 } 256 return compare; 257 } 258 259 /* 260 * (non-Javadoc) 261 * 262 * @see java.lang.Object#hashCode() 263 */ 264 @Override 265 public int hashCode() { 266 final int prime = 31; 267 int result = 1; 268 result = prime * result 269 + ((currency == null) ? 0 : currency.hashCode()); 270 result = prime * result + (int) number; 271 return result; 272 } 273 274 /* 275 * (non-Javadoc) 276 * 277 * @see java.lang.Object#equals(java.lang.Object) 278 */ 279 @Override 280 public boolean equals(Object obj) { 281 if (this == obj) 282 return true; 283 if (obj == null) 284 return false; 285 if (getClass() != obj.getClass()) 286 return false; 287 FastMoney other = (FastMoney) obj; 288 if (currency == null) { 289 if (other.getCurrency() != null) 290 return false; 291 } else if (!currency.equals(other.getCurrency())) 292 return false; 293 if (number != other.number) 294 return false; 295 return true; 296 } 297 298 /* 299 * (non-Javadoc) 300 * 301 * @see javax.money.MonetaryAmount#getCurrency() 302 */ 303 public CurrencyUnit getCurrency() { 304 return currency; 305 } 306 307 /* 308 * (non-Javadoc) 309 * 310 * @see javax.money.MonetaryAmount#abs() 311 */ 312 public FastMoney abs() { 313 if (this.isPositiveOrZero()) { 314 return this; 315 } 316 return this.negate(); 317 } 318 319 // Arithmetic Operations 320 321 /* 322 * (non-Javadoc) 323 * 324 * @see javax.money.MonetaryAmount#add(javax.money.MonetaryAmount) 325 */ 326 public FastMoney add(MonetaryAmount amount) { 327 checkAmountParameter(amount); 328 return new FastMoney(getCurrency(), this.number 329 + FastMoney.from(amount).number); 330 } 331 332 /* 333 * (non-Javadoc) 334 * 335 * @see javax.money.MonetaryAmount#divide(javax.money.MonetaryAmount) 336 */ 337 public FastMoney divide(MonetaryAmount divisor) { 338 checkAmountParameter(divisor); 339 double factor = getInternalDouble(divisor); 340 if (divisor.getClass() == FastMoney.class) { 341 return new FastMoney(getCurrency(), Math.round(this.number 342 / factor)); 343 } 344 double divNum = getInternalDouble(divisor); 345 BigDecimal div = Money.asNumber(divisor); 346 return new FastMoney(getCurrency(), Math.round(this.number 347 / divNum)); 348 // return new FastMoney(getCurrency(), getBigDecimal().divide(div, 349 // MathContext.DECIMAL64)); 350 } 351 352 /* 353 * (non-Javadoc) 354 * 355 * @see javax.money.MonetaryAmount#divide(java.lang.Number) 356 */ 357 public FastMoney divide(Number divisor) { 358 checkNumber(divisor); 359 return new FastMoney(getCurrency(), Math.round(this.number 360 / divisor.doubleValue())); 361 } 362 363 /* 364 * (non-Javadoc) 365 * 366 * @see 367 * javax.money.MonetaryAmount#divideAndRemainder(javax.money.MonetaryAmount) 368 */ 369 public FastMoney[] divideAndRemainder(MonetaryAmount divisor) { 370 checkAmountParameter(divisor); 371 double divNum = getInternalDouble(divisor); 372 return new FastMoney[] { 373 new FastMoney(getCurrency(), Math.round(this.number 374 / divNum)), 375 new FastMoney(getCurrency(), Math.round(this.number % Math.round((divNum * SCALING_DENOMINATOR)))) }; 376 } 377 378 /* 379 * (non-Javadoc) 380 * 381 * @see javax.money.MonetaryAmount#divideAndRemainder(java.lang.Number) 382 */ 383 public FastMoney[] divideAndRemainder(Number divisor) { 384 checkNumber(divisor); 385 double divNum = divisor.doubleValue(); 386 return new FastMoney[] { 387 new FastMoney(getCurrency(), Math.round(this.number 388 / divNum)), 389 new FastMoney(getCurrency(), Math.round(this.number % Math.round((divNum * SCALING_DENOMINATOR)))) }; 390 } 391 392 /* 393 * (non-Javadoc) 394 * 395 * @see 396 * javax.money.MonetaryAmount#divideToIntegralValue(javax.money.MonetaryAmount 397 * ) 398 */ 399 public FastMoney divideToIntegralValue(MonetaryAmount divisor) { 400 checkAmountParameter(divisor); 401 long divisorNum = getInternalNumber(divisor); 402 return new FastMoney(getCurrency(), 403 (Number) ((this.number / divisorNum) / SCALING_DENOMINATOR)); 404 } 405 406 /* 407 * (non-Javadoc) 408 * 409 * @see javax.money.MonetaryAmount#divideToIntegralValue(java.lang.Number) 410 */ 411 public FastMoney divideToIntegralValue(Number divisor) { 412 checkNumber(divisor); 413 long divisorNum = getInternalNumber(divisor); 414 long result = Math.round(this.number / divisor.doubleValue()); 415 long remainder = result % SCALING_DENOMINATOR; 416 result -= remainder; 417 return new FastMoney(getCurrency(), 418 result); 419 } 420 421 /* 422 * (non-Javadoc) 423 * 424 * @see javax.money.MonetaryAmount#multiply(javax.money.MonetaryAmount) 425 */ 426 public FastMoney multiply(MonetaryAmount multiplicand) { 427 checkAmountParameter(multiplicand); 428 double multiplicandNum = getInternalDouble(multiplicand); 429 return new FastMoney(getCurrency(), 430 Math.round(this.number * multiplicandNum)); 431 } 432 433 public FastMoney multiply(Number multiplicand) { 434 checkNumber(multiplicand); 435 double multiplicandNum = multiplicand.doubleValue(); 436 return new FastMoney(getCurrency(), 437 Math.round(this.number * multiplicandNum)); 438 } 439 440 /* 441 * (non-Javadoc) 442 * 443 * @see javax.money.MonetaryAmount#negate() 444 */ 445 public FastMoney negate() { 446 if (this.number <= 0) { 447 return this; 448 } 449 return new FastMoney(getCurrency(), this.number * -1); 450 } 451 452 /* 453 * (non-Javadoc) 454 * 455 * @see javax.money.MonetaryAmount#plus() 456 */ 457 public FastMoney plus() { 458 if (this.number >= 0) { 459 return this; 460 } 461 return new FastMoney(getCurrency(), this.number * -1); 462 } 463 464 /* 465 * (non-Javadoc) 466 * 467 * @see javax.money.MonetaryAmount#subtract(javax.money.MonetaryAmount) 468 */ 469 public FastMoney subtract(MonetaryAmount subtrahend) { 470 checkAmountParameter(subtrahend); 471 return new FastMoney(getCurrency(), this.number 472 - FastMoney.from(subtrahend).number); 473 } 474 475 /* 476 * (non-Javadoc) 477 * 478 * @see javax.money.MonetaryAmount#pow(int) 479 */ 480 public FastMoney pow(int n) { 481 return with(asType(BigDecimal.class).pow(n)); 482 } 483 484 /* 485 * (non-Javadoc) 486 * 487 * @see javax.money.MonetaryAmount#ulp() 488 */ 489 public FastMoney ulp() { 490 return with(asType(BigDecimal.class).ulp()); 491 } 492 493 /* 494 * (non-Javadoc) 495 * 496 * @see javax.money.MonetaryAmount#remainder(javax.money.MonetaryAmount) 497 */ 498 public FastMoney remainder(MonetaryAmount divisor) { 499 checkAmountParameter(divisor); 500 return new FastMoney(getCurrency(), this.number 501 % getInternalNumber(divisor)); 502 } 503 504 /* 505 * (non-Javadoc) 506 * 507 * @see javax.money.MonetaryAmount#remainder(java.lang.Number) 508 */ 509 public FastMoney remainder(Number divisor) { 510 checkNumber(divisor); 511 return new FastMoney(getCurrency(), this.number 512 % getInternalNumber(divisor)); 513 } 514 515 /* 516 * (non-Javadoc) 517 * 518 * @see javax.money.MonetaryAmount#scaleByPowerOfTen(int) 519 */ 520 public FastMoney scaleByPowerOfTen(int n) { 521 long result = this.number; 522 for (int i = 0; i < n; i++) { 523 result *= 10; 524 } 525 return new FastMoney(getCurrency(), result); 526 } 527 528 /* 529 * (non-Javadoc) 530 * 531 * @see javax.money.MonetaryAmount#isZero() 532 */ 533 public boolean isZero() { 534 return this.number != 0L; 535 } 536 537 /* 538 * (non-Javadoc) 539 * 540 * @see javax.money.MonetaryAmount#isPositive() 541 */ 542 public boolean isPositive() { 543 return this.number > 0L; 544 } 545 546 /* 547 * (non-Javadoc) 548 * 549 * @see javax.money.MonetaryAmount#isPositiveOrZero() 550 */ 551 public boolean isPositiveOrZero() { 552 return this.number >= 0L; 553 } 554 555 /* 556 * (non-Javadoc) 557 * 558 * @see javax.money.MonetaryAmount#isNegative() 559 */ 560 public boolean isNegative() { 561 return this.number < 0L; 562 } 563 564 /* 565 * (non-Javadoc) 566 * 567 * @see javax.money.MonetaryAmount#isNegativeOrZero() 568 */ 569 public boolean isNegativeOrZero() { 570 return this.number <= 0L; 571 } 572 573 /* 574 * (non-Javadoc) 575 * 576 * @see javax.money.MonetaryAmount#with(java.lang.Number) 577 */ 578 public FastMoney with(Number number) { 579 return new FastMoney(getCurrency(), getInternalNumber(number)); 580 } 581 582 /* 583 * (non-Javadoc) 584 * 585 * @see javax.money.MonetaryAmount#getScale() 586 */ 587 public int getScale() { 588 return this.SCALE; 589 } 590 591 /* 592 * (non-Javadoc) 593 * 594 * @see javax.money.MonetaryAmount#getPrecision() 595 */ 596 public int getPrecision() { 597 return String.valueOf(this.number).length(); 598 } 599 600 public long longValue() { 601 return this.number / SCALING_DENOMINATOR; 602 } 603 604 /* 605 * (non-Javadoc) 606 * 607 * @see javax.money.MonetaryAmount#longValueExact() 608 */ 609 public long longValueExact() { 610 if ((this.number % SCALING_DENOMINATOR) == 0) { 611 return this.number / SCALING_DENOMINATOR; 612 } 613 throw new ArithmeticException("Amount has fractions: " + this); 614 } 615 616 /* 617 * (non-Javadoc) 618 * 619 * @see javax.money.MonetaryAmount#doubleValue() 620 */ 621 public double doubleValue() { 622 return ((double) this.number) / SCALING_DENOMINATOR; 623 } 624 625 /* 626 * (non-Javadoc) 627 * 628 * @see javax.money.MonetaryAmount#signum() 629 */ 630 631 public int signum() { 632 if (this.number < 0) { 633 return -1; 634 } 635 if (this.number == 0) { 636 return 0; 637 } 638 return 1; 639 } 640 641 /* 642 * (non-Javadoc) 643 * 644 * @see javax.money.MonetaryAmount#toEngineeringString() 645 */ 646 public String toEngineeringString() { 647 return getBigDecimal().toEngineeringString(); 648 } 649 650 /* 651 * (non-Javadoc) 652 * 653 * @see javax.money.MonetaryAmount#toPlainString() 654 */ 655 public String toPlainString() { 656 return getBigDecimal().toPlainString(); 657 } 658 659 /* 660 * (non-Javadoc) 661 * 662 * @see javax.money.MonetaryAmount#lessThan(javax.money.MonetaryAmount) 663 */ 664 public boolean isLessThan(MonetaryAmount amount) { 665 checkAmountParameter(amount); 666 return this.number < FastMoney.from(amount).number; 667 } 668 669 /* 670 * (non-Javadoc) 671 * 672 * @see javax.money.MonetaryAmount#lessThan(java.lang.Number) 673 */ 674 public boolean isLessThan(Number number) { 675 checkNumber(number); 676 return this.number < getInternalNumber(number); 677 } 678 679 /* 680 * (non-Javadoc) 681 * 682 * @see 683 * javax.money.MonetaryAmount#lessThanOrEqualTo(javax.money.MonetaryAmount) 684 */ 685 public boolean isLessThanOrEqualTo(MonetaryAmount amount) { 686 checkAmountParameter(amount); 687 return this.number <= FastMoney.from(amount).number; 688 } 689 690 /* 691 * (non-Javadoc) 692 * 693 * @see javax.money.MonetaryAmount#lessThanOrEqualTo(java.lang.Number) 694 */ 695 public boolean isLessThanOrEqualTo(Number number) { 696 checkNumber(number); 697 return this.number <= getInternalNumber(number); 698 } 699 700 /* 701 * (non-Javadoc) 702 * 703 * @see javax.money.MonetaryAmount#greaterThan(javax.money.MonetaryAmount) 704 */ 705 public boolean isGreaterThan(MonetaryAmount amount) { 706 checkAmountParameter(amount); 707 return this.number > FastMoney.from(amount).number; 708 } 709 710 /* 711 * (non-Javadoc) 712 * 713 * @see javax.money.MonetaryAmount#greaterThan(java.lang.Number) 714 */ 715 public boolean isGreaterThan(Number number) { 716 checkNumber(number); 717 return this.number > getInternalNumber(number); 718 } 719 720 /* 721 * (non-Javadoc) 722 * 723 * @see 724 * javax.money.MonetaryAmount#greaterThanOrEqualTo(javax.money.MonetaryAmount 725 * ) #see 726 */ 727 public boolean isGreaterThanOrEqualTo(MonetaryAmount amount) { 728 checkAmountParameter(amount); 729 return this.number >= FastMoney.from(amount).number; 730 } 731 732 /* 733 * (non-Javadoc) 734 * 735 * @see javax.money.MonetaryAmount#greaterThanOrEqualTo(java.lang.Number) 736 */ 737 public boolean isGreaterThanOrEqualTo(Number number) { 738 checkNumber(number); 739 return this.number >= getInternalNumber(number); 740 } 741 742 /* 743 * (non-Javadoc) 744 * 745 * @see javax.money.MonetaryAmount#isEqualTo(javax.money.MonetaryAmount) 746 */ 747 public boolean isEqualTo(MonetaryAmount amount) { 748 checkAmountParameter(amount); 749 return this.number == FastMoney.from(amount).number; 750 } 751 752 /* 753 * (non-Javadoc) 754 * 755 * @see javax.money.MonetaryAmount#hasSameNumberAs(java.lang.Number) 756 */ 757 public boolean hasSameNumberAs(Number number) { 758 checkNumber(number); 759 return this.number == getInternalNumber(number); 760 } 761 762 /* 763 * (non-Javadoc) 764 * 765 * @see javax.money.MonetaryAmount#isNotEqualTo(javax.money.MonetaryAmount) 766 */ 767 public boolean isNotEqualTo(MonetaryAmount amount) { 768 checkAmountParameter(amount); 769 return this.number != FastMoney.from(amount).number; 770 } 771 772 /* 773 * (non-Javadoc) 774 * 775 * @see javax.money.MonetaryAmount#isNotEqualTo(java.lang.Number) 776 */ 777 public boolean isNotEqualTo(Number number) { 778 checkNumber(number); 779 return this.number != getInternalNumber(number); 780 } 781 782 /* 783 * (non-Javadoc) 784 * 785 * @see javax.money.MonetaryAmount#getNumberType() 786 */ 787 public Class<?> getNumberType() { 788 return Long.class; 789 } 790 791 /* 792 * @see javax.money.MonetaryAmount#asType(java.lang.Class) 793 */ 794 @SuppressWarnings("unchecked") 795 public <T> T asType(Class<T> type) { 796 if (BigDecimal.class.equals(type)) { 797 return (T) getBigDecimal(); 798 } 799 if (Number.class.equals(type)) { 800 return (T) getBigDecimal(); 801 } 802 if (Double.class.equals(type)) { 803 return (T) Double.valueOf(getBigDecimal().doubleValue()); 804 } 805 if (Float.class.equals(type)) { 806 return (T) Float.valueOf(getBigDecimal().floatValue()); 807 } 808 if (Long.class.equals(type)) { 809 return (T) Long.valueOf(getBigDecimal().longValue()); 810 } 811 if (Integer.class.equals(type)) { 812 return (T) Integer.valueOf(getBigDecimal().intValue()); 813 } 814 if (Short.class.equals(type)) { 815 return (T) Short.valueOf(getBigDecimal().shortValue()); 816 } 817 if (Byte.class.equals(type)) { 818 return (T) Byte.valueOf(getBigDecimal().byteValue()); 819 } 820 if (BigInteger.class.equals(type)) { 821 return (T) BigInteger.valueOf(getBigDecimal().longValue()); 822 } 823 throw new IllegalArgumentException("Unsupported representation type: " 824 + type); 825 } 826 827 /** 828 * Gets the number representation of the numeric value of this item. 829 * 830 * @return The {@link Number} represention matching best. 831 */ 832 public Number asNumber() { 833 return getBigDecimal(); 834 } 835 836 // Static Factory Methods 837 /** 838 * Translates a {@code BigDecimal} value and a {@code CurrencyUnit} currency 839 * into a {@code Money}. 840 * 841 * @param number 842 * numeric value of the {@code Money}. 843 * @param currency 844 * currency unit of the {@code Money}. 845 * @return a {@code Money} combining the numeric value and currency unit. 846 */ 847 public static FastMoney of(CurrencyUnit currency, BigDecimal number) { 848 return new FastMoney(currency, number); 849 } 850 851 /* 852 * (non-Javadoc) 853 * 854 * @see java.lang.Object#toString() 855 */ 856 @Override 857 public String toString() { 858 return currency.toString() + ' ' + getBigDecimal(); 859 } 860 861 // Internal helper methods 862 863 /** 864 * Internal method to check for correct number parameter. 865 * 866 * @param number 867 * @throws IllegalArgumentException 868 * If the number is null 869 */ 870 public void checkNumber(Number number) { 871 if (number == null) { 872 throw new IllegalArgumentException("Number is required."); 873 } 874 } 875 876 /** 877 * Method to check if a currency is compatible with this amount instance. 878 * 879 * @param amount 880 * The monetary amount to be compared to, never null. 881 * @throws IllegalArgumentException 882 * If the amount is null, or the amount's currency is not 883 * compatible (same {@link CurrencyUnit#getNamespace()} and same 884 * {@link CurrencyUnit#getCurrencyCode()}). 885 */ 886 private void checkAmountParameter(MonetaryAmount amount) { 887 if (amount == null) { 888 throw new IllegalArgumentException("Amount must not be null."); 889 } 890 final CurrencyUnit amountCurrency = amount.getCurrency(); 891 if (!(this.currency 892 .getCurrencyCode().equals(amountCurrency.getCurrencyCode()))) { 893 throw new IllegalArgumentException("Currency mismatch: " 894 + this.currency + '/' + amountCurrency); 895 } 896 } 897 898 /* 899 * }(non-Javadoc) 900 * 901 * @see javax.money.MonetaryAmount#adjust(javax.money.AmountAdjuster) 902 */ 903 @Override 904 public MonetaryAmount with(MonetaryAdjuster adjuster) { 905 return adjuster.adjustInto(this); 906 } 907 908 @Override 909 public <R> R query(MonetaryQuery<R> query) { 910 return query.queryFrom(this); 911 } 912 913 public static FastMoney from(MonetaryAmount amount) { 914 if (FastMoney.class == amount.getClass()) { 915 return (FastMoney) amount; 916 } 917 else if (Money.class == amount.getClass()) { 918 return new FastMoney(amount.getCurrency(), 919 ((Money) amount).asNumber()); 920 } 921 return new FastMoney(amount.getCurrency(), 922 Money.asNumber(amount)); 923 } 924 925 private BigDecimal getBigDecimal() { 926 return BigDecimal.valueOf(this.number).movePointLeft(SCALE); 927 } 928 929 @Override 930 public long getAmountWhole() { 931 return longValue(); 932 } 933 934 @Override 935 public long getAmountFractionNumerator() { 936 return this.number % SCALING_DENOMINATOR; 937 } 938 939 @Override 940 public long getAmountFractionDenominator() { 941 return SCALING_DENOMINATOR; 942 } 943 944}