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.MoneyAmountFactory;
013import org.javamoney.moneta.spi.AbstractMoney;
014import org.javamoney.moneta.spi.DefaultNumberValue;
015import org.javamoney.moneta.spi.MonetaryConfig;
016
017import javax.money.*;
018import java.io.*;
019import java.math.BigDecimal;
020import java.math.MathContext;
021import java.math.RoundingMode;
022import java.util.Locale;
023import java.util.Map;
024import java.util.Objects;
025import java.util.logging.Level;
026import java.util.logging.Logger;
027
028/**
029 * Platform RI: Default immutable implementation of {@link MonetaryAmount} based
030 * on {@link BigDecimal} for the numeric representation.
031 * <p/>
032 * As required by {@link MonetaryAmount} this class is final, thread-safe,
033 * immutable and serializable.
034 * <p/>
035 * This class can be configured with an arbitrary {@link MonetaryContext}. The
036 * default {@link MonetaryContext} used models by default the same settings as
037 * {@link MathContext#DECIMAL64} . This default {@link MonetaryContext} can also
038 * be reconfigured by adding a file {@code /javamoney.properties} to the
039 * classpath, with the following content:
040 * <p/>
041 * <pre>
042 * # Default MathContext for Money
043 * #-------------------------------
044 * # Custom MonetaryContext, overrides default entries from
045 * # org.javamoney.moneta.Money.monetaryContext
046 * # RoundingMode hereby is optional (default = HALF_EVEN)
047 * org.javamoney.moneta.Money.defaults.precision=256
048 * org.javamoney.moneta.Money.defaults.roundingMode=HALF_EVEN
049 * </pre>
050 *
051 * @author Anatole Tresch
052 * @author Werner Keil
053 * @version 0.6.1
054 */
055public final class Money extends AbstractMoney implements Comparable<MonetaryAmount>, Serializable{
056
057    /**
058     * serialVersionUID.
059     */
060    private static final long serialVersionUID = -7565813772046251748L;
061
062    /**
063     * The default {@link MonetaryContext} applied, if not set explicitly on
064     * creation.
065     */
066    public static final MonetaryContext DEFAULT_MONETARY_CONTEXT = initDefaultMathContext();
067
068    /**
069     * The numeric part of this amount.
070     */
071    private BigDecimal number;
072
073    /**
074     * Required for deserialization only.
075     */
076    private Money(){
077    }
078
079    /**
080     * Creates a new instance os {@link Money}.
081     *
082     * @param currency the currency, not null.
083     * @param number   the amount, not null.
084     * @throws ArithmeticException If the number exceeds the capabilities of the default
085     *                             {@link MonetaryContext}.
086     */
087    private Money(CurrencyUnit currency, BigDecimal number){
088        this(currency, number, null);
089    }
090
091    /**
092     * Evaluates the default {@link MonetaryContext} to be used for
093     * {@link Money}. The default {@link MonetaryContext} can be configured by
094     * adding a file {@code /javamoney.properties} from the classpath with the
095     * following content:
096     * <p/>
097     * <pre>
098     * # Default MathContext for Money
099     * #-------------------------------
100     * # Custom MathContext, overrides entries from org.javamoney.moneta.Money.mathContext
101     * # RoundingMode hereby is optional (default = HALF_EVEN)
102     * org.javamoney.moneta.Money.defaults.precision=256
103     * org.javamoney.moneta.Money.defaults.roundingMode=HALF_EVEN
104     * </pre>
105     * <p/>
106     * Hereby the roundingMode constants are the same as defined on
107     * {@link RoundingMode}.
108     *
109     * @return default MonetaryContext, never {@code null}.
110     */
111    private static MonetaryContext initDefaultMathContext(){
112        InputStream is = null;
113        try{
114            Map<String,String> config = MonetaryConfig.getConfig();
115            String value = config.get("org.javamoney.moneta.Money.defaults.precision");
116            if(value != null){
117                int prec = Integer.parseInt(value);
118                value = config.get("org.javamoney.moneta.Money.defaults.roundingMode");
119                RoundingMode rm =
120                        value != null ? RoundingMode.valueOf(value.toUpperCase(Locale.ENGLISH)) : RoundingMode.HALF_UP;
121                MonetaryContext mc =
122                        new MonetaryContext.Builder().setPrecision(prec).set(rm).setAmountType(Money.class).create();
123                Logger.getLogger(Money.class.getName())
124                        .info("Using custom MathContext: precision=" + prec + ", roundingMode=" + rm);
125                return mc;
126            }else{
127                MonetaryContext.Builder builder = new MonetaryContext.Builder(Money.class);
128                value = config.get("org.javamoney.moneta.Money.defaults.mathContext");
129                if(value != null){
130                    switch(value.toUpperCase(Locale.ENGLISH)){
131                        case "DECIMAL32":
132                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL32");
133                            builder.set(MathContext.DECIMAL32);
134                            break;
135                        case "DECIMAL64":
136                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL64");
137                            builder.set(MathContext.DECIMAL64);
138                            break;
139                        case "DECIMAL128":
140                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL128");
141                            builder.set(MathContext.DECIMAL128);
142                            break;
143                        case "UNLIMITED":
144                            Logger.getLogger(Money.class.getName()).info("Using MathContext.UNLIMITED");
145                            builder.set(MathContext.UNLIMITED);
146                            break;
147                    }
148                }else{
149                    Logger.getLogger(Money.class.getName()).info("Using default MathContext.DECIMAL64");
150                    builder.set(MathContext.DECIMAL64);
151                }
152                return builder.create();
153            }
154        }
155        catch(Exception e){
156            Logger.getLogger(Money.class.getName())
157                    .log(Level.SEVERE, "Error evaluating default NumericContext, using default (NumericContext.NUM64).",
158                         e);
159            return new MonetaryContext.Builder(Money.class).set(MathContext.DECIMAL64).create();
160        }
161        finally{
162            if(is != null){
163                try{
164                    is.close();
165                }
166                catch(IOException e){
167                    Logger.getLogger(Money.class.getName())
168                            .log(Level.WARNING, "Error closing InputStream after evaluating default NumericContext.",
169                                 e);
170                }
171            }
172        }
173    }
174
175    /**
176     * Creates a new instance of {@link Money}.
177     *
178     * @param currency        the currency, not {@code null}.
179     * @param number          the amount, not {@code null}.
180     * @param monetaryContext the {@link MonetaryContext}, if {@code null}, the default is
181     *                        used.
182     * @throws ArithmeticException If the number exceeds the capabilities of the
183     *                             {@link MonetaryContext} used.
184     */
185    private Money(CurrencyUnit currency, BigDecimal number, MonetaryContext monetaryContext){
186        super(currency, monetaryContext);
187        Objects.requireNonNull(number, "Number is required.");
188        if(monetaryContext != null){
189            this.number = getBigDecimal(number, monetaryContext);
190        }else{
191            this.number = getBigDecimal(number, DEFAULT_MONETARY_CONTEXT);
192        }
193    }
194
195    /*
196     * (non-Javadoc)
197     *
198     * @see javax.money.MonetaryAmount#getNumber()
199     */
200    public NumberValue getNumber(){
201        return new DefaultNumberValue(number);
202    }
203
204    /**
205     * Method that returns BigDecimal.ZERO, if {@link #isZero()}, and
206     * {@link #number #stripTrailingZeros()} in all other cases.
207     *
208     * @return the stripped number value.
209     */
210    public BigDecimal getNumberStripped(){
211        if(isZero()){
212            return BigDecimal.ZERO;
213        }
214        return this.number.stripTrailingZeros();
215    }
216
217    /*
218     * @see java.lang.Comparable#compareTo(java.lang.Object)
219     */
220    @Override
221    public int compareTo(MonetaryAmount o){
222        Objects.requireNonNull(o);
223        int compare = getCurrency().getCurrencyCode().compareTo(o.getCurrency().getCurrencyCode());
224        if(compare == 0){
225            compare = this.number.compareTo(Money.from(o).number);
226        }
227        return compare;
228    }
229
230    // Arithmetic Operations
231
232    /*
233     * (non-Javadoc)
234     *
235     * @see javax.money.MonetaryAmount#abs()
236     */
237    @Override
238    public Money abs(){
239        if(this.isPositiveOrZero()){
240            return this;
241        }
242        return negate();
243    }
244
245    /*
246     * (non-Javadoc)
247     *
248     * @see javax.money.MonetaryAmount#divide(javax.money.MonetaryAmount)
249     */
250    @Override
251    public Money divide(long divisor){
252        if(divisor == 1L){
253            return this;
254        }
255        return divide(BigDecimal.valueOf(divisor));
256    }
257
258    /*
259     * (non-Javadoc)
260     *
261     * @see javax.money.MonetaryAmount#divide(javax.money.MonetaryAmount)
262     */
263    @Override
264    public Money divide(double divisor){
265        if(divisor == 1.0){
266            return this;
267        }
268        return divide(new BigDecimal(String.valueOf(divisor)));
269    }
270
271    /*
272     * (non-Javadoc)
273     *
274     * @see
275     * javax.money.MonetaryAmount#divideAndRemainder(javax.money.MonetaryAmount)
276     */
277    @Override
278    public Money[] divideAndRemainder(long divisor){
279        return divideAndRemainder(BigDecimal.valueOf(divisor));
280    }
281
282    /*
283     * (non-Javadoc)
284     *
285     * @see
286     * javax.money.MonetaryAmount#divideAndRemainder(javax.money.MonetaryAmount)
287     */
288    @Override
289    public Money[] divideAndRemainder(double divisor){
290        return divideAndRemainder(new BigDecimal(String.valueOf(divisor)));
291    }
292
293    /*
294     * (non-Javadoc)
295     *
296     * @see javax.money.MonetaryAmount#multiply(Number)
297     */
298    @Override
299    public Money multiply(long multiplicand){
300        return multiply(BigDecimal.valueOf(multiplicand));
301    }
302
303    /*
304     * (non-Javadoc)
305     *
306     * @see javax.money.MonetaryAmount#multiply(Number)
307     */
308    @Override
309    public Money multiply(double multiplicand){
310        return multiply(new BigDecimal(String.valueOf(multiplicand)));
311    }
312
313    /*
314     * (non-Javadoc)
315     *
316     * @see javax.money.MonetaryAmount#remainder(Number)
317     */
318    @Override
319    public Money remainder(long divisor){
320        return remainder(BigDecimal.valueOf(divisor));
321    }
322
323    /*
324     * (non-Javadoc)
325     *
326     * @see javax.money.MonetaryAmount#remainder(Number)
327     */
328    @Override
329    public Money remainder(double divisor){
330        return remainder(new BigDecimal(String.valueOf(divisor)));
331    }
332
333    /*
334     * (non-Javadoc)
335     *
336     * @see javax.money.MonetaryAmount#isZero()
337     */
338    @Override
339    public boolean isZero(){
340        return signum() == 0;
341    }
342
343    /*
344     * (non-Javadoc)
345     *
346     * @see javax.money.MonetaryAmount#isPositive()
347     */
348    @Override
349    public boolean isPositive(){
350        return signum() == 1;
351    }
352
353    /*
354     * (non-Javadoc)
355     *
356     * @see javax.money.MonetaryAmount#isPositiveOrZero()
357     */
358    @Override
359    public boolean isPositiveOrZero(){
360        return signum() >= 0;
361    }
362
363    /*
364     * (non-Javadoc)
365     *
366     * @see javax.money.MonetaryAmount#isNegative()
367     */
368    @Override
369    public boolean isNegative(){
370        return signum() == -1;
371    }
372
373    /*
374     * (non-Javadoc)
375     *
376     * @see javax.money.MonetaryAmount#isNegativeOrZero()
377     */
378    @Override
379    public boolean isNegativeOrZero(){
380        return signum() <= 0;
381    }
382
383    // /*
384    // * (non-Javadoc)
385    // *
386    // * @see javax.money.MonetaryAmount#with(javax.money.CurrencyUnit, long)
387    // */
388    // @Override
389    // public Money with(CurrencyUnit unit, long amount) {
390    // return with(unit, BigDecimal.valueOf(amount));
391    // }
392    //
393    // /*
394    // * (non-Javadoc)
395    // *
396    // * @see javax.money.MonetaryAmount#with(javax.money.CurrencyUnit, double)
397    // */
398    // @Override
399    // public Money with(CurrencyUnit unit, double amount) {
400    // return with(unit, new BigDecimal(String.valueOf(amount)));
401    // }
402
403    /*
404     * }(non-Javadoc)
405     *
406     * @see javax.money.MonetaryAmount#query(javax.money.MonetaryQuery)
407     */
408    @Override
409    public <R> R query(MonetaryQuery<R> query){
410        Objects.requireNonNull(query);
411        try{
412            return query.queryFrom(this);
413        }
414        catch(Exception e){
415            throw new MonetaryException("Query failed: " + query, e);
416        }
417    }
418
419    /*
420     * (non-Javadoc)
421     *
422     * @see javax.money.MonetaryAmount#with(javax.money.MonetaryOperator)
423     */
424    @Override
425    public Money with(MonetaryOperator operator){
426        Objects.requireNonNull(operator);
427        try{
428            return Money.class.cast(operator.apply(this));
429        }
430        catch(Exception e){
431            throw new MonetaryException("Operator failed: " + operator, e);
432        }
433    }
434
435    /*
436     * (non-Javadoc)
437     *
438     * @see javax.money.MonetaryAmount#add(javax.money.MonetaryAmount)
439     */
440    @Override
441    public Money add(MonetaryAmount amount){
442        checkAmountParameter(amount);
443        if(amount.isZero()){
444            return this;
445        }
446        return new Money(getCurrency(), this.number.add(amount.getNumber().numberValue(BigDecimal.class)));
447    }
448
449    /*
450     * (non-Javadoc)
451     *
452     * @see javax.money.MonetaryAmount#divide(java.lang.Number)
453     */
454    @Override
455    public Money divide(Number divisor){
456        BigDecimal divisorBD = getBigDecimal(divisor);
457        if(divisorBD.equals(BigDecimal.ONE)){
458            return this;
459        }
460        BigDecimal dec = this.number.divide(divisorBD, getMathContext(getMonetaryContext(), RoundingMode.HALF_EVEN));
461        return new Money(getCurrency(), dec);
462    }
463
464    @Override
465    public Money[] divideAndRemainder(Number divisor){
466        BigDecimal divisorBD = getBigDecimal(divisor);
467        if(divisorBD.equals(BigDecimal.ONE)){
468            return new Money[]{this, new Money(getCurrency(), BigDecimal.ZERO)};
469        }
470        BigDecimal[] dec = this.number.divideAndRemainder(divisorBD);
471        return new Money[]{new Money(getCurrency(), dec[0]), new Money(getCurrency(), dec[1])};
472    }
473
474    /*
475     * (non-Javadoc)
476     *
477     * @see
478     * org.javamoney.moneta.AbstractMoney#divideToIntegralValue(java.lang.Number
479     * )
480     */
481    @Override
482    public Money divideToIntegralValue(long divisor){
483        return divideToIntegralValue(getBigDecimal(divisor));
484    }
485
486    @Override
487    public Money divideToIntegralValue(double divisor){
488        return divideToIntegralValue(getBigDecimal(divisor));
489    }
490
491    @Override
492    public Money divideToIntegralValue(Number divisor){
493        BigDecimal divisorBD = getBigDecimal(divisor);
494        BigDecimal dec = this.number.divideToIntegralValue(divisorBD);
495        return new Money(getCurrency(), dec);
496    }
497
498    /*
499     * (non-Javadoc)
500     *
501     * @see org.javamoney.moneta.AbstractMoney#multiply(java.lang.Number)
502     */
503    @Override
504    public Money multiply(Number multiplicand){
505        BigDecimal multiplicandBD = getBigDecimal(multiplicand);
506        if(multiplicandBD.equals(BigDecimal.ONE)){
507            return this;
508        }
509        BigDecimal dec = this.number.multiply(multiplicandBD);
510        return new Money(getCurrency(), dec);
511    }
512
513    /*
514     * (non-Javadoc)
515     *
516     * @see javax.money.MonetaryAmount#negate()
517     */
518    @Override
519    public Money negate(){
520        return new Money(getCurrency(), this.number.negate());
521    }
522
523    /*
524     * (non-Javadoc)
525     *
526     * @see javax.money.MonetaryAmount#plus()
527     */
528    @Override
529    public Money plus(){
530        return new Money(getCurrency(), this.number.plus());
531    }
532
533    /*
534     * (non-Javadoc)
535     *
536     * @see javax.money.MonetaryAmount#subtract(javax.money.MonetaryAmount)
537     */
538    @Override
539    public Money subtract(MonetaryAmount subtrahend){
540        checkAmountParameter(subtrahend);
541        if(subtrahend.isZero()){
542            return this;
543        }
544        return new Money(getCurrency(), this.number.subtract(subtrahend.getNumber().numberValue(BigDecimal.class)));
545    }
546
547    /*
548     * (non-Javadoc)
549     *
550     * @see javax.money.MonetaryAmount#stripTrailingZeros()
551     */
552    @Override
553    public Money stripTrailingZeros(){
554        if(isZero()){
555            return new Money(getCurrency(), BigDecimal.ZERO);
556        }
557        return new Money(getCurrency(), this.number.stripTrailingZeros());
558    }
559
560    /*
561     * (non-Javadoc)
562     *
563     * @see org.javamoney.moneta.AbstractMoney#remainder(java.math.BigDecimal)
564     */
565    @Override
566    public Money remainder(Number divisor){
567        BigDecimal bd = getBigDecimal(divisor);
568        return new Money(getCurrency(), this.number.remainder(bd));
569    }
570
571    /*
572     * (non-Javadoc)
573     *
574     * @see javax.money.MonetaryAmount#scaleByPowerOfTen(int)
575     */
576    @Override
577    public Money scaleByPowerOfTen(int n){
578        return new Money(getCurrency(), this.number.scaleByPowerOfTen(n));
579    }
580
581    /*
582     * (non-Javadoc)
583     *
584     * @see javax.money.MonetaryAmount#signum()
585     */
586    @Override
587    public int signum(){
588        return this.number.signum();
589    }
590
591    /*
592     * (non-Javadoc)
593     *
594     * @see javax.money.MonetaryAmount#isLessThan(javax.money.MonetaryAmount)
595     */
596    @Override
597    public boolean isLessThan(MonetaryAmount amount){
598        checkAmountParameter(amount);
599        return number.compareTo(Money.from(amount).number) < 0;
600    }
601
602    /*
603     * (non-Javadoc)
604     *
605     * @see
606     * javax.money.MonetaryAmount#isLessThanOrEqualTo(javax.money.MonetaryAmount
607     * )
608     */
609    @Override
610    public boolean isLessThanOrEqualTo(MonetaryAmount amount){
611        checkAmountParameter(amount);
612        return number.compareTo(Money.from(amount).number) <= 0;
613    }
614
615    /*
616     * (non-Javadoc)
617     *
618     * @see javax.money.MonetaryAmount#isGreaterThan(javax.money.MonetaryAmount)
619     */
620    @Override
621    public boolean isGreaterThan(MonetaryAmount amount){
622        checkAmountParameter(amount);
623        return number.compareTo(Money.from(amount).number) > 0;
624    }
625
626    /*
627     * (non-Javadoc)
628     *
629     * @see
630     * javax.money.MonetaryAmount#isGreaterThanOrEqualTo(javax.money.MonetaryAmount
631     * ) #see
632     */
633    @Override
634    public boolean isGreaterThanOrEqualTo(MonetaryAmount amount){
635        checkAmountParameter(amount);
636        return number.compareTo(Money.from(amount).number) >= 0;
637    }
638
639    /*
640     * (non-Javadoc)
641     *
642     * @see javax.money.MonetaryAmount#isEqualTo(javax.money.MonetaryAmount)
643     */
644    @Override
645    public boolean isEqualTo(MonetaryAmount amount){
646        checkAmountParameter(amount);
647        return equals(Money.from(amount));
648    }
649
650    /*
651     * (non-Javadoc)
652     *
653     * @see javax.money.MonetaryAmount#getFactory()
654     */
655    @Override
656    public MonetaryAmountFactory<Money> getFactory(){
657        return new MoneyAmountFactory().setAmount(this);
658    }
659
660    /*
661     * (non-Javadoc)
662     *
663     * @see org.javamoney.moneta.AbstractMoney#getDefaultMonetaryContext()
664     */
665    @Override
666    protected MonetaryContext getDefaultMonetaryContext(){
667        return DEFAULT_MONETARY_CONTEXT;
668    }
669
670    /**
671     * Implement serialization explicitly.
672     */
673    private void writeObject(ObjectOutputStream oos) throws IOException{
674        oos.writeObject(this.number);
675        oos.writeObject(this.currency);
676        oos.writeObject(this.monetaryContext);
677    }
678
679    /*
680     * (non-Javadoc)
681     *
682     * @see java.lang.Object#equals(java.lang.Object)
683     */
684    @Override
685    public boolean equals(Object obj){
686        if(this == obj)
687            return true;
688        if(obj == null)
689            return false;
690        if(getClass() != obj.getClass())
691            return false;
692        Money other = (Money) obj;
693        if(!getCurrency().equals(other.getCurrency()))
694            return false;
695        return getNumberStripped().equals(other.getNumberStripped());
696    }
697
698    /*
699     * (non-Javadoc)
700     *
701     * @see java.lang.Object#toString()
702     */
703    @Override
704    public String toString(){
705        return getCurrency().getCurrencyCode() + ' ' + number.toString();
706    }
707
708    /**
709     * Implement deserialization explicitly.
710     */
711    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
712        this.number = (BigDecimal) ois.readObject();
713        this.currency = (CurrencyUnit) ois.readObject();
714        this.monetaryContext = (MonetaryContext) ois.readObject();
715    }
716
717    @SuppressWarnings("unused")
718    private void readObjectNoData() throws ObjectStreamException{
719        if(this.number == null){
720            this.number = BigDecimal.ZERO;
721        }
722        if(this.monetaryContext == null){
723            this.monetaryContext = DEFAULT_MONETARY_CONTEXT;
724        }
725    }
726
727    /*
728     * (non-Javadoc)
729     *
730     * @see java.lang.Object#hashCode()
731     */
732    @Override
733    public int hashCode(){
734        final int prime = 31;
735        int result = 1;
736        result = prime * result + getCurrency().hashCode();
737        return prime * result + getNumberStripped().hashCode();
738    }
739
740    /**
741     * Creates a new instance of {@link Money}, using the default
742     * {@link MonetaryContext}.
743     *
744     * @param number   numeric value, not {@code null}.
745     * @param currency currency unit, not {@code null}.
746     * @return a {@code Money} combining the numeric value and currency unit.
747     * @throws ArithmeticException If the number exceeds the capabilities of the default
748     *                             {@link MonetaryContext} used.
749     */
750    public static Money of(CurrencyUnit currency, BigDecimal number){
751        return new Money(currency, number);
752    }
753
754    /**
755     * Creates a new instance of {@link Money}, using an explicit
756     * {@link MonetaryContext}.
757     *
758     * @param number          numeric value, not {@code null}.
759     * @param currency        currency unit, not {@code null}.
760     * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the
761     *                        default {@link MonetaryContext} is used.
762     * @return a {@code Money} instance based on the monetary context with the
763     * given numeric value, currency unit.
764     * @throws ArithmeticException If the number exceeds the capabilities of the
765     *                             {@link MonetaryContext} used.
766     */
767    public static Money of(CurrencyUnit currency, BigDecimal number, MonetaryContext monetaryContext){
768        return new Money(currency, number, monetaryContext);
769    }
770
771    /**
772     * Creates a new instance of {@link Money}, using the default
773     * {@link MonetaryContext}.
774     *
775     * @param currency The target currency, not null.
776     * @param number   The numeric part, not null.
777     * @return A new instance of {@link Money}.
778     * @throws ArithmeticException If the number exceeds the capabilities of the default
779     *                             {@link MonetaryContext} used.
780     */
781    public static Money of(CurrencyUnit currency, Number number){
782        return new Money(currency, getBigDecimal(number));
783    }
784
785    /**
786     * Creates a new instance of {@link Money}, using an explicit
787     * {@link MonetaryContext}.
788     *
789     * @param currency        The target currency, not null.
790     * @param number          The numeric part, not null.
791     * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the
792     *                        default {@link MonetaryContext} is used.
793     * @return A new instance of {@link Money}.
794     * @throws ArithmeticException If the number exceeds the capabilities of the
795     *                             {@link MonetaryContext} used.
796     */
797    public static Money of(CurrencyUnit currency, Number number, MonetaryContext monetaryContext){
798        return new Money(currency, getBigDecimal(number), monetaryContext);
799    }
800
801    /**
802     * Static factory method for creating a new instance of {@link Money}.
803     *
804     * @param currencyCode The target currency as ISO currency code.
805     * @param number       The numeric part, not null.
806     * @return A new instance of {@link Money}.
807     */
808    public static Money of(String currencyCode, Number number){
809        return new Money(MonetaryCurrencies.getCurrency(currencyCode), getBigDecimal(number));
810    }
811
812    /**
813     * Static factory method for creating a new instance of {@link Money}.
814     *
815     * @param currencyCode The target currency as ISO currency code.
816     * @param number       The numeric part, not null.
817     * @return A new instance of {@link Money}.
818     */
819    public static Money of(String currencyCode, BigDecimal number){
820        return new Money(MonetaryCurrencies.getCurrency(currencyCode), number);
821    }
822
823    /**
824     * Static factory method for creating a new instance of {@link Money}.
825     *
826     * @param currencyCode    The target currency as ISO currency code.
827     * @param number          The numeric part, not null.
828     * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the
829     *                        default {@link MonetaryContext} is used.
830     * @return A new instance of {@link Money}.
831     */
832    public static Money of(String currencyCode, Number number, MonetaryContext monetaryContext){
833        return new Money(MonetaryCurrencies.getCurrency(currencyCode), getBigDecimal(number), monetaryContext);
834    }
835
836    /**
837     * Static factory method for creating a new instance of {@link Money}.
838     *
839     * @param currencyCode    The target currency as ISO currency code.
840     * @param number          The numeric part, not null.
841     * @param monetaryContext the {@link MonetaryContext} to be used, if {@code null} the
842     *                        default {@link MonetaryContext} is used.
843     * @return A new instance of {@link Money}.
844     */
845    public static Money of(String currencyCode, BigDecimal number, MonetaryContext monetaryContext){
846        return new Money(MonetaryCurrencies.getCurrency(currencyCode), number, monetaryContext);
847    }
848
849    /**
850     * Converts (if necessary) the given {@link MonetaryAmount} to a
851     * {@link Money} instance. The {@link MonetaryContext} will be adapted as
852     * necessary, if the precision of the given amount exceeds the capabilities
853     * of the default {@link MonetaryContext}.
854     *
855     * @param amt the amount to be converted
856     * @return an according Money instance.
857     */
858    public static Money from(MonetaryAmount amt){
859        if(amt.getClass() == Money.class){
860            return (Money) amt;
861        }
862        return Money.of(amt.getCurrency(), amt.getNumber().numberValue(BigDecimal.class), amt.getMonetaryContext());
863    }
864
865}