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