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