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