001/*
002 * Copyright (c) 2012, 2013, Credit Suisse (Anatole Tresch), Werner Keil. Licensed under the Apache
003 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the
004 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
005 * Unless required by applicable law or agreed to in writing, software distributed under the License
006 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
007 * or implied. See the License for the specific language governing permissions and limitations under
008 * the License.
009 */
010package org.javamoney.moneta;
011
012import org.javamoney.moneta.internal.RoundedMoneyAmountFactory;
013import org.javamoney.moneta.spi.AbstractMoney;
014import org.javamoney.moneta.spi.DefaultNumberValue;
015
016import javax.money.*;
017import java.io.*;
018import java.math.BigDecimal;
019import java.math.BigInteger;
020import java.math.MathContext;
021import java.math.RoundingMode;
022import java.util.Objects;
023
024/**
025 * Platform RI: Default immutable implementation of {@link MonetaryAmount} based on
026 * {@link BigDecimal} for the numeric representation.
027 * <p/>
028 * As required by {@link MonetaryAmount} this class is final, thread-safe, immutable and
029 * serializable.
030 *
031 * @author Anatole Tresch
032 * @author Werner Keil
033 * @version 0.6.1
034 */
035public final class RoundedMoney extends AbstractMoney implements Comparable<MonetaryAmount>, Serializable{
036
037    /**
038     * serialVersionUID.
039     */
040    private static final long serialVersionUID = 366517590511294389L;
041    /**
042     * The default {@link MonetaryContext} applied.
043     */
044    public static final MonetaryContext DEFAULT_MONETARY_CONTEXT =
045            MonetaryContext.from(Money.DEFAULT_MONETARY_CONTEXT, RoundedMoney.class);
046
047    /**
048     * The numeric part of this amount.
049     */
050    private BigDecimal number;
051
052    /**
053     * The rounding to be done.
054     */
055    private MonetaryOperator rounding;
056
057    /**
058     * Required for deserialization only.
059     */
060    private RoundedMoney(){
061    }
062
063    /**
064     * Creates a new instance os {@link RoundedMoney}.
065     *
066     * @param currency the currency, not null.
067     * @param number   the amount, not null.
068     */
069    private RoundedMoney(CurrencyUnit currency, Number number, MonetaryContext monetaryContext,
070                         MonetaryOperator rounding){
071        super(currency, monetaryContext);
072        Objects.requireNonNull(number, "Number is required.");
073        checkNumber(number);
074        this.currency = currency;
075        if(rounding != null){
076            this.rounding = rounding;
077        }else{
078            this.rounding = MonetaryRoundings.getRounding(currency);
079        }
080        this.number = getBigDecimal(number, monetaryContext);
081    }
082
083    // Static Factory Methods
084
085    /**
086     * Translates a {@code BigDecimal} value and a {@code CurrencyUnit} currency into a
087     * {@code Money}.
088     *
089     * @param number   numeric value of the {@code Money}.
090     * @param currency currency unit of the {@code Money}.
091     * @return a {@code Money} combining the numeric value and currency unit.
092     */
093    public static RoundedMoney of(CurrencyUnit currency, BigDecimal number){
094        return new RoundedMoney(currency, number, DEFAULT_MONETARY_CONTEXT, null);
095    }
096
097    /**
098     * Translates a {@code BigDecimal} value and a {@code CurrencyUnit} currency into a
099     * {@code Money}.
100     *
101     * @param number   numeric value of the {@code Money}.
102     * @param currency currency unit of the {@code Money}.
103     * @param rounding The rounding to be applied.
104     * @return a {@code Money} combining the numeric value and currency unit.
105     */
106    public static RoundedMoney of(CurrencyUnit currency, BigDecimal number, MonetaryOperator rounding){
107        return new RoundedMoney(currency, number, DEFAULT_MONETARY_CONTEXT, rounding);
108    }
109
110    /**
111     * Translates a {@code BigDecimal} value and a {@code CurrencyUnit} currency into a
112     * {@code Money}.
113     *
114     * @param number          numeric value of the {@code Money}.
115     * @param currency        currency unit of the {@code Money}.
116     * @param monetaryContext the {@link MathContext} to be used.
117     * @return a {@code Money} combining the numeric value and currency unit.
118     */
119    public static RoundedMoney of(CurrencyUnit currency, BigDecimal number, MonetaryContext monetaryContext){
120        return new RoundedMoney(currency, number, MonetaryContext.from(monetaryContext, RoundedMoney.class), null);
121    }
122
123    /**
124     * Translates a {@code BigDecimal} value and a {@code CurrencyUnit} currency into a
125     * {@code Money}.
126     *
127     * @param number      numeric value of the {@code Money}.
128     * @param currency    currency unit of the {@code Money}.
129     * @param mathContext the {@link MathContext} to be used.
130     * @param rounding    The rounding to be applied.
131     * @return a {@code Money} combining the numeric value and currency unit.
132     */
133    public static RoundedMoney of(CurrencyUnit currency, BigDecimal number, MonetaryContext monetaryContext,
134                                  MonetaryOperator rounding){
135        return new RoundedMoney(currency, number, MonetaryContext.from(monetaryContext, RoundedMoney.class), rounding);
136    }
137
138    /**
139     * Static factory method for creating a new instance of {@link RoundedMoney} .
140     *
141     * @param currency The target currency, not null.
142     * @param number   The numeric part, not null.
143     * @return A new instance of {@link RoundedMoney}.
144     */
145    public static RoundedMoney of(CurrencyUnit currency, Number number){
146        return new RoundedMoney(currency, number, (MonetaryContext) null, null);
147    }
148
149    /**
150     * Static factory method for creating a new instance of {@link RoundedMoney} .
151     *
152     * @param currency The target currency, not null.
153     * @param number   The numeric part, not null.
154     * @param rounding The rounding to be applied.
155     * @return A new instance of {@link RoundedMoney}.
156     */
157    public static RoundedMoney of(CurrencyUnit currency, Number number, MonetaryOperator rounding){
158        return new RoundedMoney(currency, number, (MonetaryContext) null, rounding);
159    }
160
161    /**
162     * Static factory method for creating a new instance of {@link RoundedMoney} .
163     *
164     * @param currency The target currency, not null.
165     * @param number   The numeric part, not null.
166     * @return A new instance of {@link RoundedMoney}.
167     */
168    public static RoundedMoney of(CurrencyUnit currency, Number number, MonetaryContext monetaryContext){
169        return new RoundedMoney(currency, number, MonetaryContext.from(monetaryContext, RoundedMoney.class), null);
170    }
171
172    /**
173     * Static factory method for creating a new instance of {@link RoundedMoney} .
174     *
175     * @param currency        The target currency, not null.
176     * @param number          The numeric part, not null.
177     * @param monetaryContext the {@link MonetaryContext} to be used.
178     * @param rounding        The rounding to be applied.
179     * @return A new instance of {@link RoundedMoney}.
180     */
181    public static RoundedMoney of(CurrencyUnit currency, Number number, MonetaryContext monetaryContext,
182                                  MonetaryOperator rounding){
183        return new RoundedMoney(currency, number, MonetaryContext.from(monetaryContext, RoundedMoney.class), rounding);
184    }
185
186    /**
187     * Static factory method for creating a new instance of {@link RoundedMoney} .
188     *
189     * @param isoCurrencyCode The target currency as ISO currency code.
190     * @param number          The numeric part, not null.
191     * @return A new instance of {@link RoundedMoney}.
192     */
193    public static RoundedMoney of(String currencyCode, Number number){
194        return new RoundedMoney(MonetaryCurrencies.getCurrency(currencyCode), number, DEFAULT_MONETARY_CONTEXT,
195                                MonetaryRoundings.getRounding(MonetaryCurrencies.getCurrency(currencyCode)));
196    }
197
198    /**
199     * Static factory method for creating a new instance of {@link RoundedMoney} .
200     *
201     * @param isoCurrencyCode The target currency as ISO currency code.
202     * @param number          The numeric part, not null.
203     * @param rounding        The rounding to be applied.
204     * @return A new instance of {@link RoundedMoney}.
205     */
206    public static RoundedMoney of(String currencyCode, Number number, MonetaryOperator rounding){
207        return new RoundedMoney(MonetaryCurrencies.getCurrency(currencyCode), number, DEFAULT_MONETARY_CONTEXT,
208                                rounding);
209    }
210
211    /**
212     * Static factory method for creating a new instance of {@link RoundedMoney} .
213     *
214     * @param isoCurrencyCode 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    public static RoundedMoney of(String currencyCode, Number number, MonetaryContext monetaryContext){
219        return new RoundedMoney(MonetaryCurrencies.getCurrency(currencyCode), number,
220                                MonetaryContext.from(monetaryContext, RoundedMoney.class),
221                                MonetaryRoundings.getRounding(monetaryContext));
222    }
223
224    /**
225     * Static factory method for creating a new instance of {@link RoundedMoney} .
226     *
227     * @param isoCurrencyCode 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(String currencyCode, Number number, MonetaryContext monetaryContext,
233                                  MonetaryOperator rounding){
234        return new RoundedMoney(MonetaryCurrencies.getCurrency(currencyCode), number,
235                                MonetaryContext.from(monetaryContext, RoundedMoney.class), rounding);
236    }
237
238    /*
239     * (non-Javadoc)
240     * @see javax.money.MonetaryAmount#getCurrency()
241     */
242    public CurrencyUnit getCurrency(){
243        return currency;
244    }
245
246    /**
247     * Access the {@link MathContext} used by this instance.
248     *
249     * @return the {@link MathContext} used, never null.
250     */
251    public MonetaryContext getMonetaryContext(){
252        return this.monetaryContext;
253    }
254
255    public RoundedMoney abs(){
256        if(this.isPositiveOrZero()){
257            return this;
258        }
259        return this.negate();
260    }
261
262    // Arithmetic Operations
263
264    public RoundedMoney add(MonetaryAmount amount){
265        checkAmountParameter(amount);
266        return (RoundedMoney) new RoundedMoney(this.currency,
267                                               this.number.add(amount.getNumber().numberValue(BigDecimal.class)),
268                                               this.monetaryContext, this.rounding).with(rounding);
269    }
270
271    /*
272     * (non-Javadoc)
273     * @see javax.money.MonetaryAmount#divide(javax.money.MonetaryAmount)
274     */
275    public RoundedMoney divide(Number divisor){
276
277        BigDecimal dec = this.number.divide(getBigDecimal(divisor), this.monetaryContext
278                .getAttribute(RoundingMode.class, RoundingMode.HALF_EVEN));
279        return (RoundedMoney) new RoundedMoney(this.currency, dec, this.monetaryContext, this.rounding).with(rounding);
280    }
281
282    /*
283     * (non-Javadoc)
284     * @see javax.money.MonetaryAmount#divideAndRemainder(javax.money.MonetaryAmount)
285     */
286    public RoundedMoney[] divideAndRemainder(Number divisor){
287        BigDecimal[] dec = this.number.divideAndRemainder(getBigDecimal(divisor), this.monetaryContext
288                .getAttribute(MathContext.class, MathContext.DECIMAL64));
289        return new RoundedMoney[]{new RoundedMoney(this.currency, dec[0], this.monetaryContext, this.rounding),
290                (RoundedMoney) new RoundedMoney(this.currency, dec[1], this.monetaryContext, this.rounding)
291                        .with(rounding)};
292    }
293
294    /*
295     * (non-Javadoc)
296     * @see javax.money.MonetaryAmount#divideToIntegralValue(Number) )D
297     */
298    public RoundedMoney divideToIntegralValue(Number divisor){
299        BigDecimal dec = this.number.divideToIntegralValue(getBigDecimal(divisor), this.monetaryContext
300                .getAttribute(MathContext.class, MathContext.DECIMAL64));
301        return new RoundedMoney(this.currency, dec, this.monetaryContext, this.rounding);
302    }
303
304    /*
305     * (non-Javadoc)
306     * @see javax.money.MonetaryAmount#multiply(Number)
307     */
308    public RoundedMoney multiply(Number multiplicand){
309        BigDecimal dec = this.number.multiply(getBigDecimal(multiplicand), this.monetaryContext
310                .getAttribute(MathContext.class, MathContext.DECIMAL64));
311        return (RoundedMoney) new RoundedMoney(this.currency, dec, this.monetaryContext, this.rounding).with(rounding);
312    }
313
314    /*
315     * (non-Javadoc)
316     * @see javax.money.MonetaryAmount#negate()
317     */
318    public RoundedMoney negate(){
319        return new RoundedMoney(this.currency, this.number
320                .negate(this.monetaryContext.getAttribute(MathContext.class, MathContext.DECIMAL64)),
321                                this.monetaryContext, this.rounding);
322    }
323
324    /*
325     * (non-Javadoc)
326     * @see javax.money.MonetaryAmount#plus()
327     */
328    public RoundedMoney plus(){
329        return new RoundedMoney(this.currency, this.number
330                .plus(this.monetaryContext.getAttribute(MathContext.class, MathContext.DECIMAL64)),
331                                this.monetaryContext, this.rounding);
332    }
333
334    /*
335     * (non-Javadoc)
336     * @see javax.money.MonetaryAmount#subtract(javax.money.MonetaryAmount)
337     */
338    public RoundedMoney subtract(MonetaryAmount subtrahend){
339        checkAmountParameter(subtrahend);
340        if(subtrahend.isZero()){
341            return this;
342        }
343        return new RoundedMoney(this.currency, this.number
344                .subtract(subtrahend.getNumber().numberValue(BigDecimal.class),
345                          this.monetaryContext.getAttribute(MathContext.class, MathContext.DECIMAL64)),
346                                this.monetaryContext, this.rounding);
347    }
348
349    /*
350     * (non-Javadoc)
351     * @see javax.money.MonetaryAmount#pow(int)
352     */
353    public RoundedMoney pow(int n){
354        return new RoundedMoney(this.currency, this.number
355                .pow(n, this.monetaryContext.getAttribute(MathContext.class, MathContext.DECIMAL64)),
356                                this.monetaryContext, this.rounding).with(rounding);
357    }
358
359    /*
360     * (non-Javadoc)
361     * @see javax.money.MonetaryAmount#ulp()
362     */
363    public RoundedMoney ulp(){
364        return new RoundedMoney(this.currency, this.number.ulp(), DEFAULT_MONETARY_CONTEXT, this.rounding);
365    }
366
367    /*
368     * (non-Javadoc)
369     * @see javax.money.MonetaryAmount#remainder(Number)
370     */
371    public RoundedMoney remainder(Number divisor){
372        return new RoundedMoney(this.currency, this.number.remainder(getBigDecimal(divisor), this.monetaryContext
373                .getAttribute(MathContext.class, MathContext.DECIMAL64)), this.monetaryContext, this.rounding);
374    }
375
376    /*
377     * (non-Javadoc)
378     * @see javax.money.MonetaryAmount#scaleByPowerOfTen(int)
379     */
380    public RoundedMoney scaleByPowerOfTen(int n){
381        return new RoundedMoney(this.currency, this.number.scaleByPowerOfTen(n), this.monetaryContext, this.rounding);
382    }
383
384    /*
385     * (non-Javadoc)
386     * @see javax.money.MonetaryAmount#isZero()
387     */
388    public boolean isZero(){
389        return this.number.signum() == 0;
390    }
391
392    /*
393     * (non-Javadoc)
394     * @see javax.money.MonetaryAmount#isPositive()
395     */
396    public boolean isPositive(){
397        return signum() == 1;
398    }
399
400    /*
401     * (non-Javadoc)
402     * @see javax.money.MonetaryAmount#isPositiveOrZero()
403     */
404    public boolean isPositiveOrZero(){
405        return signum() >= 0;
406    }
407
408    /*
409     * (non-Javadoc)
410     * @see javax.money.MonetaryAmount#isNegative()
411     */
412    public boolean isNegative(){
413        return signum() == -1;
414    }
415
416    /*
417     * (non-Javadoc)
418     * @see javax.money.MonetaryAmount#isNegativeOrZero()
419     */
420    public boolean isNegativeOrZero(){
421        return signum() <= 0;
422    }
423
424    /*
425     * (non-Javadoc)
426     * @see javax.money.MonetaryAmount#with(java.lang.Number)
427     */
428    public RoundedMoney with(Number amount){
429        checkNumber(amount);
430        return new RoundedMoney(this.currency, getBigDecimal(amount), this.monetaryContext, this.rounding);
431    }
432
433    /**
434     * Creates a new Money instance, by just replacing the {@link CurrencyUnit}.
435     *
436     * @param currency the currency unit to be replaced, not {@code null}
437     * @return the new amount with the same numeric value and {@link MathContext}, but the new
438     * {@link CurrencyUnit}.
439     */
440    public RoundedMoney with(CurrencyUnit currency){
441        Objects.requireNonNull(currency, "currency required");
442        return new RoundedMoney(currency, asType(BigDecimal.class), this.monetaryContext, this.rounding);
443    }
444
445    /*
446     * (non-Javadoc)
447     * @see javax.money.MonetaryAmount#with(CurrencyUnit, java.lang.Number)
448     */
449    public RoundedMoney with(CurrencyUnit currency, Number amount){
450        checkNumber(amount);
451        return new RoundedMoney(currency, getBigDecimal(amount), this.monetaryContext, this.rounding);
452    }
453
454    /*
455     * (non-Javadoc)
456     * @see javax.money.MonetaryAmount#getScale()
457     */
458    public int getScale(){
459        return this.number.scale();
460    }
461
462    /*
463     * (non-Javadoc)
464     * @see javax.money.MonetaryAmount#getPrecision()
465     */
466    public int getPrecision(){
467        return this.number.precision();
468    }
469
470        /*
471     * (non-Javadoc)
472         * @see javax.money.MonetaryAmount#signum()
473         */
474
475    public int signum(){
476        return this.number.signum();
477    }
478
479    /*
480     * (non-Javadoc)
481     * @see javax.money.MonetaryAmount#lessThan(javax.money.MonetaryAmount)
482     */
483    public boolean isLessThan(MonetaryAmount amount){
484        checkAmountParameter(amount);
485        return number.compareTo(amount.getNumber().numberValue(BigDecimal.class)) < 0;
486    }
487
488    /*
489     * (non-Javadoc)
490     * @see javax.money.MonetaryAmount#lessThanOrEqualTo(javax.money.MonetaryAmount)
491     */
492    public boolean isLessThanOrEqualTo(MonetaryAmount amount){
493        checkAmountParameter(amount);
494        return number.compareTo(amount.getNumber().numberValue(BigDecimal.class)) <= 0;
495    }
496
497    /*
498     * (non-Javadoc)
499     * @see javax.money.MonetaryAmount#greaterThan(javax.money.MonetaryAmount)
500     */
501    public boolean isGreaterThan(MonetaryAmount amount){
502        checkAmountParameter(amount);
503        return number.compareTo(amount.getNumber().numberValue(BigDecimal.class)) > 0;
504    }
505
506    /*
507     * (non-Javadoc)
508     * @see javax.money.MonetaryAmount#greaterThanOrEqualTo(javax.money.MonetaryAmount ) #see
509     */
510    public boolean isGreaterThanOrEqualTo(MonetaryAmount amount){
511        checkAmountParameter(amount);
512        return number.compareTo(amount.getNumber().numberValue(BigDecimal.class)) >= 0;
513    }
514
515    /*
516     * (non-Javadoc)
517     * @see javax.money.MonetaryAmount#isEqualTo(javax.money.MonetaryAmount)
518     */
519    public boolean isEqualTo(MonetaryAmount amount){
520        checkAmountParameter(amount);
521        return number.compareTo(amount.getNumber().numberValue(BigDecimal.class)) == 0;
522    }
523
524    /*
525     * (non-Javadoc)
526     * @see javax.money.MonetaryAmount#isNotEqualTo(javax.money.MonetaryAmount)
527     */
528    public boolean isNotEqualTo(MonetaryAmount amount){
529        checkAmountParameter(amount);
530        return number.compareTo(amount.getNumber().numberValue(BigDecimal.class)) != 0;
531    }
532
533    /*
534     * }(non-Javadoc)
535     * @see javax.money.MonetaryAmount#adjust(javax.money.AmountAdjuster)
536     */
537    @Override
538    public RoundedMoney with(MonetaryOperator operator){
539        Objects.requireNonNull(operator);
540        try{
541            return RoundedMoney.from(operator.apply(this));
542        }
543        catch(Exception e){
544            throw new MonetaryException("Query failed: " + operator, e);
545        }
546    }
547
548    public static RoundedMoney from(MonetaryAmount amt){
549        if(amt.getClass() == RoundedMoney.class){
550            return (RoundedMoney) amt;
551        }
552        if(amt.getClass() == FastMoney.class){
553            return RoundedMoney.of(amt.getCurrency(), ((FastMoney) amt).getNumber().numberValue(BigDecimal.class),
554                                   DEFAULT_MONETARY_CONTEXT);
555        }else if(amt.getClass() == Money.class){
556            return RoundedMoney
557                    .of(amt.getCurrency(), amt.getNumber().numberValue(BigDecimal.class), DEFAULT_MONETARY_CONTEXT);
558        }
559        return RoundedMoney
560                .of(amt.getCurrency(), amt.getNumber().numberValue(BigDecimal.class), DEFAULT_MONETARY_CONTEXT);
561    }
562
563    /*
564     * }(non-Javadoc)
565     * @see javax.money.MonetaryAmount#adjust(javax.money.AmountAdjuster)
566     */
567    @Override
568    public <T> T query(MonetaryQuery<T> query){
569        Objects.requireNonNull(query);
570        try{
571            return query.queryFrom(this);
572        }
573        catch(Exception e){
574            throw new MonetaryException("Query failed: " + query, e);
575        }
576    }
577
578    /*
579     * @see javax.money.MonetaryAmount#asType(java.lang.Class)
580     */
581    @SuppressWarnings("unchecked")
582    public <T> T asType(Class<T> type){
583        if(BigDecimal.class.equals(type)){
584            return (T) this.number;
585        }
586        if(Number.class.equals(type)){
587            final T asType = (T) this.number;
588            return asType;
589        }
590        if(Double.class.equals(type)){
591            return (T) Double.valueOf(this.number.doubleValue());
592        }
593        if(Float.class.equals(type)){
594            return (T) Float.valueOf(this.number.floatValue());
595        }
596        if(Long.class.equals(type)){
597            return (T) Long.valueOf(this.number.longValue());
598        }
599        if(Integer.class.equals(type)){
600            return (T) Integer.valueOf(this.number.intValue());
601        }
602        if(Short.class.equals(type)){
603            return (T) Short.valueOf(this.number.shortValue());
604        }
605        if(Byte.class.equals(type)){
606            return (T) Byte.valueOf(this.number.byteValue());
607        }
608        if(BigInteger.class.equals(type)){
609            return (T) this.number.toBigInteger();
610        }
611        throw new IllegalArgumentException("Unsupported representation type: " + type);
612    }
613
614    /*
615     * }(non-Javadoc)
616     * @see javax.money.MonetaryAmount#asType(java.lang.Class, javax.money.Rounding)
617     */
618    public <T> T asType(Class<T> type, MonetaryOperator adjuster){
619        RoundedMoney amount = (RoundedMoney) adjuster.apply(this);
620        return amount.asType(type);
621    }
622
623    private void writeObject(ObjectOutputStream oos) throws IOException{
624        oos.writeObject(this.number);
625        oos.writeObject(this.monetaryContext);
626        oos.writeObject(this.currency);
627    }
628
629    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
630        this.number = (BigDecimal) ois.readObject();
631        this.monetaryContext = (MonetaryContext) ois.readObject();
632        this.currency = (CurrencyUnit) ois.readObject();
633    }
634
635    @SuppressWarnings("unused")
636    private void readObjectNoData() throws ObjectStreamException{
637        if(this.number == null){
638            this.number = BigDecimal.ZERO;
639        }
640        if(this.monetaryContext == null){
641            this.monetaryContext = DEFAULT_MONETARY_CONTEXT;
642        }
643        if(this.currency == null){
644            this.currency = MonetaryCurrencies.getCurrency("XXX"); // no
645            // currency
646        }
647    }
648
649    /*
650     * (non-Javadoc)
651     * @see java.lang.Object#toString()
652     */
653    @Override
654    public String toString(){
655        return currency.getCurrencyCode() + ' ' + number;
656    }
657
658    /*
659     * (non-Javadoc)
660     * @see java.lang.Object#hashCode()
661     */
662    @Override
663    public int hashCode(){
664        final int prime = 31;
665        int result = 1;
666        result = prime * result + ((currency == null) ? 0 : currency.hashCode());
667        return prime * result + asNumberStripped().hashCode();
668    }
669
670    /*
671     * (non-Javadoc)
672     * @see java.lang.Object#equals(java.lang.Object)
673     */
674    @Override
675    public boolean equals(Object obj){
676        if(this == obj)
677            return true;
678        if(obj == null)
679            return false;
680        if(getClass() != obj.getClass())
681            return false;
682        RoundedMoney other = (RoundedMoney) obj;
683        if(currency == null){
684            if(other.currency != null)
685                return false;
686        }else if(!currency.equals(other.currency))
687            return false;
688        return asNumberStripped().equals(other.asNumberStripped());
689    }
690
691    /*
692     * @see java.lang.Comparable#compareTo(java.lang.Object)
693     */
694    public int compareTo(MonetaryAmount o){
695        Objects.requireNonNull(o);
696        int compare = -1;
697        if(this.currency.equals(o.getCurrency())){
698            compare = asNumberStripped().compareTo(RoundedMoney.from(o).asNumberStripped());
699        }else{
700            compare = this.currency.getCurrencyCode().compareTo(o.getCurrency().getCurrencyCode());
701        }
702        return compare;
703    }
704
705    /*
706     * (non-Javadoc)
707     * @see javax.money.MonetaryAmount#getNumber()
708     */
709    public NumberValue getNumber(){
710        return new DefaultNumberValue(number);
711    }
712
713    /**
714     * Method that returns BigDecimal.ZERO, if {@link #isZero()}, and #number
715     * {@link #stripTrailingZeros()} in all other cases.
716     *
717     * @return the stripped number value.
718     */
719    public BigDecimal asNumberStripped(){
720        if(isZero()){
721            return BigDecimal.ZERO;
722        }
723        return this.number.stripTrailingZeros();
724    }
725
726    /**
727     * Internal method to check for correct number parameter.
728     *
729     * @param number
730     * @throws IllegalArgumentException If the number is null
731     */
732    private void checkNumber(Number number){
733        Objects.requireNonNull(number, "Number is required.");
734    }
735
736    @Override
737    public RoundedMoney multiply(long amount){
738        return multiply(getBigDecimal(amount));
739    }
740
741    @Override
742    public RoundedMoney multiply(double amount){
743        return multiply(getBigDecimal(amount));
744    }
745
746    @Override
747    public RoundedMoney divide(long amount){
748        return divide(getBigDecimal(amount));
749    }
750
751    @Override
752    public RoundedMoney divide(double amount){
753        return divide(getBigDecimal(amount));
754    }
755
756    @Override
757    public RoundedMoney remainder(long amount){
758        return remainder(getBigDecimal(amount));
759    }
760
761    @Override
762    public RoundedMoney remainder(double amount){
763        return remainder(getBigDecimal(amount));
764    }
765
766    @Override
767    public RoundedMoney[] divideAndRemainder(long amount){
768        return divideAndRemainder(getBigDecimal(amount));
769    }
770
771    @Override
772    public RoundedMoney[] divideAndRemainder(double amount){
773        return divideAndRemainder(getBigDecimal(amount));
774    }
775
776    @Override
777    public RoundedMoney stripTrailingZeros(){
778        if(isZero()){
779            return of(getCurrency(), BigDecimal.ZERO);
780        }
781        return of(getCurrency(), this.number.stripTrailingZeros());
782    }
783
784    @Override
785    public RoundedMoney divideToIntegralValue(long divisor){
786        return divideToIntegralValue(getBigDecimal(divisor));
787    }
788
789    @Override
790    public RoundedMoney divideToIntegralValue(double divisor){
791        return divideToIntegralValue(getBigDecimal(divisor));
792    }
793
794    @Override
795    protected MonetaryContext getDefaultMonetaryContext(){
796        return DEFAULT_MONETARY_CONTEXT;
797    }
798
799    @Override
800    public MonetaryAmountFactory<RoundedMoney> getFactory(){
801        return new RoundedMoneyAmountFactory().setAmount(this);
802    }
803}