We would like to know how to create Money type based on BigDecimal.
/*from w ww . j av a2 s . com*/ //package org.groovyflow.util; import java.math.BigDecimal; import java.text.NumberFormat; import java.util.List; import java.util.Locale; public class Money implements Comparable, java.io.Serializable { private static final String ZERO_STRING = "0"; private static final Money ZERO_MONEY = new Money(ZERO_STRING); private BigDecimal delegate; public static Money getMoneyThatHasZeroValue(){ return ZERO_MONEY; } public static Money getInfiniteMoney(){ Long x = Long.MAX_VALUE; return new Money(x.toString()); } public Money(String val) { this.delegate = new BigDecimal(val); if(delegate.scale() > 2) throw new IllegalArgumentException("Money can't have scale > 2"); delegate.setScale(2); } public Money(BigDecimal value){ this(value.toString()); } public Money add(Money val){ return new Money(delegate.add(val.delegate)); } public Money subtract(Money val){ return new Money(delegate.subtract(val.delegate)); } public BigDecimal multiply(BigDecimal val){ return delegate.multiply(val); } /** * returns Money . If roundCeiling is true we rounded up to * the nearest cent, otherwise we round down. Note that rounding toward the ceiling * always rounds to positive infinity (so, for example, -$0.031 becomes * -$0.03). When roundCeiling is false we round toward the floor, so in that case * -$0.031 becomes-$0.04. This is exactly as BigDecimal.ROUND_CEILING and * BigDecimal.ROUND_FLOOR behave. * @see java.math.BigDecimal.ROUND_CEILING */ public Money multiplyAndRound(BigDecimal val, boolean roundCeiling){ BigDecimal product = delegate.multiply(val); int rounding = roundCeiling ? BigDecimal.ROUND_CEILING : BigDecimal.ROUND_FLOOR; return new Money(product.setScale(2, rounding)); } /** * Sets scale to 2 and returns a Money object. */ public Money divideAndReturnMoney(BigDecimal val, int roundingMode){ return new Money(delegate.divide(val, 2, roundingMode)); } /** *Round the return value before turning it into a Money object by passing it into the Money constructor. */ public BigDecimal divide(BigDecimal val, int scale, int roundingMode) { return delegate.divide(val, scale, roundingMode); } public BigDecimal divide(Money val, int scale, int roundingMode){ return divide(val.delegate, scale, roundingMode); } public BigDecimal getBigDecimalValue(){ return new BigDecimal(delegate.toString()); } // Comparison Operations public boolean gt(Money val){ return compareTo(val) > 0; } public boolean gtEq(Money val){ return compareTo(val) >= 0; } public boolean lt(Money val){ return compareTo(val) < 0; } public boolean ltEq(Money val){ return compareTo(val) <= 0; } public boolean gtZero(){ return gt(ZERO_MONEY); } public boolean gtEqZero(){ return gtEq(ZERO_MONEY); } public boolean ltZero(){ return lt(ZERO_MONEY); } public boolean ltEqZero(){ return ltEq(ZERO_MONEY); } public int compareTo(Money val){ return delegate.compareTo(val.delegate); } public int compareTo(Object o) { return compareTo((Money)o); } /** * Will return true if x is a Money object and x's private BigDecimal delegate * has the same value as our private BigDecimal delegate, regardless of scale. * A subtle point: BigDecimal's .equal() requires that the scale of the compared * BigDecimals are the same, while the current class's .equals does not require that. * In fact, this .equals behaves like BigDecimal's .compareTo(). */ public boolean equals(Object x){ if(!(x instanceof Money)) return false; Money brother = (Money) x; return (delegate.compareTo(brother.delegate) == 0); } public boolean equalsZeroMoney(){ return this.equals(ZERO_MONEY); } public Money negate(){ return ZERO_MONEY.subtract(this); } /** * Returns -1 if this is less than zero money, 0 if equal to zero money, 1 if greater than zero money. */ public int compareToZeroMoney(){ return this.compareTo(ZERO_MONEY); } public Money min(Money val){ return new Money((delegate.min(val.delegate)).toString()); } public Money max(Money val){ return new Money((delegate.max(val.delegate)).toString()); } public Money abs(){ return new Money( delegate.abs().toString() ); } public int hashCode() { return delegate.hashCode(); } /** *Prints money with two decimal points. */ public String toString(){ if(delegate == null) return null; //setting scale to 2 won't really force scale to 2 if we have something like 10 or 10.0, so //we have to do the following. int realScale = delegate.scale(); if(realScale == 2) return delegate.toString(); else if(realScale == 1) return delegate.toString() + "0"; else if (realScale == 0) return delegate.toString() + ".00"; else throw new RuntimeException("Scale of money object is > 2, should never happen, Money object is faulty."); } /** * Front end re-wrote displayAsDollars so that it displays a negative amount without the * negative sign. If you want something sensible, use displayAsDollarsCorrectly instead. */ public String displayAsDollarsCorrectly(){ if ( delegate.signum() < 0 ) { this.delegate = delegate.negate(); String dis = "-$" + this.toString(); this.delegate = this.delegate.negate(); return dis; } else { return "$" + toString(); } } public String displayAsDollars(){ NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.US); if ( delegate.signum() < 0 ) { this.delegate = delegate.negate(); //String dis = "-$" + this.toString(); this.delegate = this.delegate.negate(); //return dis; return nf.format(this.delegate); } else { return nf.format(this.delegate); //return "$" + toString(); } } public int intValue(){ return delegate.intValue(); } /** *Null elements in the argument array will not cause things to blow up with a NullPointerException. *Instead they will be ignored, because we foresee some circumstances in which a caller *might have a sparsely populated array it wants summed up. Note that call this class's *add(Money) method one at a time does not, as of this writing, share this behavior. Instead *it will just blow up. */ public static Money add(Money[] moneys){ //Attempt to save on object creation by adding up the BigDecimal //delegates. So rather than creating a Money and a BigDecimal //with each element of the sum, we're just creating a BigDecimal. BigDecimal total = new BigDecimal("0"); for(int i = 0; i < moneys.length; i++){ if(moneys[i] != null){ total = total.add(moneys[i].getBigDecimalValue()); } } return new Money(total); } public static Money add(List moneys){ Money[] arr = (Money[]) moneys.toArray(new Money[moneys.size()]); return add(arr); } public static Money returnNullAsZero(Money money){ return (money == null) ? getMoneyThatHasZeroValue() : money; } }