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