Money.java
package com.tradecloud.domain.model;
import com.tradecloud.domain.base.utils.MathUtils;
import com.tradecloud.domain.wrapper.CurrencyXmlAdapter;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Currency;
@Embeddable
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Money")
public class Money implements Comparable<Money>, Serializable {
private static final long serialVersionUID = 1L;
@XmlJavaTypeAdapter(CurrencyXmlAdapter.class)
private Currency currency;
@Column(precision = 19, scale = 15)
private BigDecimal value;
private static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_UP;
public static Money zeroValue(Currency currency) {
return new Money(BigDecimal.ZERO, currency);
}
public static Money valueOf(BigDecimal results, String currency) {
return new Money(results, Currency.getInstance(currency));
}
public Money zeroValue() {
return zeroValue(currency);
// return new Money(BigDecimal.ZERO, currency);
}
private static void validateAmountLength(String value) {
if (value != null && value.length() > 30) {
throw new IllegalArgumentException("Invalid value, amount too big");
}
}
// For JPA only
protected Money() {
}
//copy constructor
public Money(Money toCopy) {
this.value = toCopy.getValue();
this.currency = toCopy.getCurrency();
}
public Money(Currency currency) {
this(BigDecimal.ZERO, currency);
}
public Money(String currencyStr) {
this(BigDecimal.ZERO, Currency.getInstance(currencyStr));
}
public Money(com.tradecloud.domain.common.Currency currency) {
this(Currency.getInstance(currency.getCode()));
}
public Money(double value, String currencyStr) {
this(new BigDecimal(value), Currency.getInstance(currencyStr));
}
public Money(BigDecimal value, com.tradecloud.domain.common.Currency currency) {
this(value, Currency.getInstance(currency.getCode()));
}
public Money(BigDecimal value, Currency currency) {
this(value, currency, null);
}
private Money(BigDecimal value, Currency currency, Integer overrideDefaultScale) {
this.value = setValueScale(value, overrideDefaultScale);
this.currency = currency;
}
public boolean isZero() {
return value.compareTo(BigDecimal.ZERO) == 0;
}
public boolean isNegative() {
return value.compareTo(BigDecimal.ZERO) == -1;
}
public boolean isPositive() {
return value.compareTo(BigDecimal.ZERO) == 1;
}
public static Money valueOf(String value, Currency currency) {
BigDecimal valueBigD = parseNumber(value);
return new Money(valueBigD, currency);
}
public static Money valueOf(BigDecimal value, Currency currency) {
return new Money(value, currency);
}
public static Money valueOf(String value, com.tradecloud.domain.common.Currency currency) {
BigDecimal valueBigD = parseNumber(value);
return new Money(valueBigD, currency);
}
private static BigDecimal parseNumber(String value) {
validateAmountLength(value);
try {
return new BigDecimal(removeCommasFrom(value));
} catch (NumberFormatException exc) {
throw new RuntimeException("Invalid value, numeric expected [" + value + "]");
}
}
private static String removeCommasFrom(String value) {
return value.replaceAll(",", "");
}
private static BigDecimal setValueScale(BigDecimal value, Integer overrideDefaultScale) {
int scaleValue = 6;
if (overrideDefaultScale != null)
scaleValue = overrideDefaultScale;
return value.setScale(scaleValue, DEFAULT_ROUNDING_MODE);
}
public static BigDecimal parseValue(String amountValue) {
return setValueScale(parseNumber(amountValue), null);
}
public Money divide(Money money) {
assertThatCurrenciesAreTheSame(money);
return new Money(this.value.divide(money.getValue(), 15, DEFAULT_ROUNDING_MODE), this.currency);
}
public Money divide(int money) {
BigDecimal divisor = new BigDecimal(money);
divisor = divisor.setScale(this.getValue().scale());
return new Money(this.value.divide(divisor, 15, DEFAULT_ROUNDING_MODE), this.currency);
}
public Money divideRate(Money money) {
if (this.currency.equals(money.getCurrency())) {
throw new IllegalArgumentException("Currencies should not be the same when dividing an amount by a rate : "
+ this.getCurrency().getCurrencyCode() + " and " + money.getCurrency().getCurrencyCode());
}
return new Money(this.value.divide(money.getValue(), 15, DEFAULT_ROUNDING_MODE), money.getCurrency(),15);
}
public static boolean areNumbersCloselyEqual(BigDecimal lhsNumber, BigDecimal rhsNumber, int precision) {
return MathUtils.areNumbersCloselyEqual(lhsNumber, rhsNumber, precision);
}
public static boolean areNumbersCloselyEqual(double lhsNumber, double rhsNumber, int precision) {
return MathUtils.areNumbersCloselyEqual(lhsNumber, rhsNumber, precision);
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public String getPrettyValue() {
return getValue().setScale(2, DEFAULT_ROUNDING_MODE).toString();
}
public Currency getCurrency() {
return currency;
}
public Money add(Money money) {
assertThatCurrenciesAreTheSame(money);
return new Money(this.value.add(money.getValue()), this.currency);
}
public Money subtract(Money money) {
assertThatCurrenciesAreTheSame(money);
return new Money(this.value.subtract(money.getValue()), this.currency);
}
public Money multiply(Money money) {
assertThatCurrenciesAreTheSame(money);
return new Money(this.value.multiply(money.getValue()), this.currency);
}
public Money multiply(Money money, int overrideDefaultScale) {
assertThatCurrenciesAreTheSame(money);
return new Money(this.value.multiply(money.getValue()), this.currency, overrideDefaultScale);
}
public Money multiply(BigDecimal value) {
return new Money(this.value.multiply(value), currency);
}
public Money multiplyRate(Money money) {
if (this.currency.equals(money.getCurrency())) {
throw new IllegalArgumentException("Currencies should not be the same when multiplying an amount by a rate : "
+ this.getCurrency().getCurrencyCode() + " and " + money.getCurrency().getCurrencyCode());
}
return new Money(this.value.multiply(money.getValue()), money.getCurrency());
}
public Money negate() {
return new Money(value.multiply(new BigDecimal("-1")), currency);
}
private void assertThatCurrenciesAreTheSame(Money money) throws IllegalArgumentException {
if (!this.currency.equals(money.getCurrency())) {
throw new IllegalArgumentException("Currency mismatch between " + this.getCurrency().getCurrencyCode() + " and "
+ money.getCurrency().getCurrencyCode());
}
}
public boolean lessThan(Money rhs) {
return this.getValue().compareTo(rhs.getValue()) < 0 && this.getCurrency().equals(rhs.getCurrency());
}
public boolean lessThanOrEqual(Money rhs) {
return (this.getValue().compareTo(rhs.getValue()) < 0 || equals(rhs)) && this.getCurrency().equals(rhs.getCurrency());
}
public boolean greaterThan(Money rhs) {
return rhs.lessThan(this);
}
public boolean greaterThanOrEqual(Money rhs) {
return (this.getValue().compareTo(rhs.getValue()) > 0 || equals(rhs)) && this.getCurrency().equals(rhs.getCurrency());
}
@Override
public Money clone() {
return new Money(value, currency);
}
@Override
public boolean equals(Object obj) {
// TODO. Use EqualsBuilder
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Money other = (Money) obj;
if (!this.currency.equals(other.currency)) {
return false;
}
if (!(this.value.compareTo(other.value) == 0)) {
return false;
}
return true;
}
@Override
public int hashCode() {
// TODO. Use HashcodeBuilder
int hash = 3;
hash = 71 * hash + (this.currency != null ? this.currency.hashCode() : 0);
hash = 71 * hash + (this.value != null ? this.value.hashCode() : 0);
return hash;
}
@Override
public int compareTo(Money m) {
assertThatCurrenciesAreTheSame(m);
return this.value.compareTo(m.getValue());
}
@Override
public String toString() {
return currency.getCurrencyCode() + value.toPlainString();
}
public Money abs() {
return new Money(value.abs(), currency);
}
}