
com.github.daytron.daytronmoney.currency.MoneyFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of DaytronMoney Show documentation
Show all versions of DaytronMoney Show documentation
A Java library for dealing simple monetary operations and conversions.
The newest version!
/*
* The MIT License
*
* Copyright 2015 Ryan Gilera.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.github.daytron.daytronmoney.currency;
import com.github.daytron.daytronmoney.utility.StringUtil;
import java.util.Currency;
import java.util.Locale;
/**
* A factory class for instantiating Money
objects. Parses other
* data types into a Money
object.
*
* @author Ryan Gilera
*/
public class MoneyFactory {
private static final String DEFAULT_CURRENCY_CODE
= Currency.getInstance(Locale.getDefault()).getCurrencyCode();
private String currencyCode;
/**
* Default constructor. Applies default local currency code.
*/
public MoneyFactory() {
this(DEFAULT_CURRENCY_CODE);
}
/**
* Optional constructor with specific currency code as an input.
*
* @param currencyCode A String
object that represents a
* currency code (Three letter currency code)
*/
public MoneyFactory(String currencyCode) {
currencyCode = currencyCode.trim();
this.currencyCode = (Currency.getInstance(
currencyCode.toUpperCase())).getCurrencyCode();
}
/**
* Optional constructor with Locale constant as its input. Please note that
* only Locale country constants are allowed. A language-based Local constants
* throws an exception.
*
* @param locale A Locale
country constant
*/
public MoneyFactory(Locale locale) {
this.currencyCode = Currency.getInstance(locale).getCurrencyCode();
}
/**
* Returns the currency code.
*
* @return A String
object
*/
public String getCurrencyCode() {
return currencyCode;
}
/**
* Sets the currency code.
*
* @param currencyCode A String
object that represents a
* currency code (Three letter currency code)
*/
public void setCurrencyCode(String currencyCode) {
currencyCode = currencyCode.trim();
this.currencyCode = (Currency.getInstance(
currencyCode.toUpperCase())).getCurrencyCode();
}
/**
* Creates a zero Money for no-argument input.
*
* @return Resulting Money
object
*/
public Money valueOf() {
return new Money.Builder()
.currencyCode(currencyCode)
.sign(SignValue.Positive)
.build();
}
/**
* Creates a Money
object from parsing it's
* long
argument. Default sign is positive if
* value is greater than 0.
*
* @param value A long
value to be parsed
* @return Resulting Money
object
*/
public Money valueOf(long value) {
SignValue sign = SignValue.Positive;
if (value < 0) {
sign = SignValue.Negative;
value = Math.abs(value);
}
return new Money.Builder()
.currencyCode(currencyCode)
.sign(sign)
.wholeUnit(value)
.build();
}
/**
* Creates a Money
object from parsing its
* int
argument. Default sign is positive if
* value is greater than 0.
*
* @param value An integer
value to be parsed
* @return Resulting Money
object
*/
public Money valueOf(int value) {
return valueOf((long)value);
}
/**
* Creates a Money
object from parsing
* its long
arguments. First argument represents the whole unit
* , the second for its decimal unit and last argument for its leading zeroes.
* Default sign is positive if value is greater than 0.
*
* @param wholeUnit A long
value to be parsed as whole unit
* @param decimalUnit A long
value to be parsed as decimal unit
* @param leadingDecimalZeros A long
value to be parsed as
* leading zeroes
* @return Resulting Money
object
*/
public Money valueOf(long wholeUnit, long decimalUnit,
long leadingDecimalZeros) {
SignValue sign = SignValue.Positive;
if (wholeUnit < 0 || decimalUnit < 0) {
sign = SignValue.Negative;
wholeUnit = Math.abs(wholeUnit);
decimalUnit = Math.abs(decimalUnit);
}
return new Money.Builder()
.currencyCode(this.currencyCode)
.sign(sign)
.wholeUnit(wholeUnit)
.decimalUnit(decimalUnit)
.leadingDecimalZeroes(leadingDecimalZeros)
.build();
}
/**
* Creates a Money
object from parsing a String
* value. Possible inputs include:
*
* - "GBP 12.5"
* - "GBP12.5"
* - "USD-12"
* - "USD -896,586,785,785,896.0025634589"
* - ""
* - "+9.6212"
* - "-8.0000000"
* - "0.00"
* - "-0"
* - "-0.12"
* - "0"
* - "286"
* - "0.0000005"
* - "000000000000000.6"
* - "12,856,896.00963"
*
*
* @param valueString A String
object to be parsed
* @return Resulting Money
object
*/
public Money valueOf(String valueString) {
valueString = valueString.trim();
if (valueString == null) {
throw new NullPointerException("Null input!");
}
if (valueString.isEmpty()) {
return new Money.Builder()
.currencyCode(currencyCode)
.sign(SignValue.Positive)
.build();
}
String[] resultParsedValue = StringUtil.parseAndRemoveCurrencyCode(valueString);
valueString = resultParsedValue[1];
String newCurrencyCode;
if (resultParsedValue[0].isEmpty()) {
newCurrencyCode = this.currencyCode;
} else {
newCurrencyCode = (Currency.getInstance(
resultParsedValue[0])).getCurrencyCode();
}
long[] parsedData = parseValue(valueString);
SignValue sign;
long wholeUnit, decimalUnit, leadingDecimalZeros;
// Parse sign
sign = ((parsedData[0] == 1)?SignValue.Positive:SignValue.Negative);
wholeUnit = parsedData[1];
decimalUnit = parsedData[2];
leadingDecimalZeros = parsedData[3];
// Normalise sign and leading zero
if (wholeUnit == 0 && decimalUnit == 0) {
leadingDecimalZeros = 0;
sign = SignValue.Positive;
}
return new Money.Builder()
.currencyCode(newCurrencyCode)
.sign(sign)
.wholeUnit(wholeUnit)
.decimalUnit(decimalUnit)
.leadingDecimalZeroes(leadingDecimalZeros)
.build();
}
/**
* Parse String to long values as long arrays.
*
* @param valueString A String
object to be parsed
* @return A long
array
*/
private static long[] parseValue(String valueString) {
// First element = sign 1 for positive and 0 for negative
// Second element for pounds
// Third element for pence
final long[] parsedData = new long[4];
// Removes commas
// Allows to accept number string with commas
valueString = StringUtil.removeCommas(valueString);
/*
Regex conditions:
^ = Beginning of the line
[+-]? = Optional Sign
[0-9]{1,19} = 1 or 19 digits including zero
\\. = Literal point symbol,
(escaped, because in regex, . is a special character)
(\\.[0-9]{1,19})? = An optional decimal value must have at least
one digit after the dot
$ = End of the line.
*/
if (valueString.matches("^[-+]?[0-9]{1,19}(\\.[0-9]{1,19})?$")) {
// Determines sign and then removes it
// 1 for positive and 0 for negative
if (valueString.contains("-")) {
parsedData[0] = 0;
// Removes sign
valueString = valueString.substring(1);
} else if (valueString.contains("+")) {
parsedData[0] = 1;
// Removes sign
valueString = valueString.substring(1);
} else {
parsedData[0] = 1;
}
String[] splitString = valueString.split("\\.");
if (splitString.length > 1) {
parsedData[1] = Long.valueOf(splitString[0]);
// Filters single digit decimal number as two digits
// Ex. 1.2 is 1.20 and NOT 1.02
if (splitString[1].length() == 1 &&
splitString[1].charAt(0) != '0') {
splitString[1] += "0";
}
// Filter if all decimal values are pure repeating zeroes
// Otherwise process remaining zeroess
if (splitString[1].matches("[0]{1,}")) {
parsedData[2] = 0;
parsedData[3] = 0;
} else {
long decimalResult[] =
StringUtil.analyzeDecimalValue(splitString[1]);
parsedData[2] = decimalResult[1];
parsedData[3] = decimalResult[0];
}
} else {
parsedData[1] = Long.valueOf(splitString[0]);
parsedData[2] = 0;
parsedData[3] = 0;
}
return parsedData;
} else if ((valueString.indexOf('.', valueString.indexOf('.') + 1) != -1)) {
/*
Throws an illegal argument exeption if multiple occurences of dot
are detected in the argument input.
*/
throw new IllegalArgumentException("Invalid number entry. "
+ "Multiple dots detected.");
} else if (valueString.charAt(0) == '.' || valueString.contains("+.")
|| valueString.contains("-.")) {
/*
Throws an illegal argument exception if a dot is detected in
the first character or any sign followed by a dot.
*/
throw new IllegalArgumentException("Invalid number entry. "
+ "Invalid use of decimal point.");
} else if (valueString.matches("^[-+]{2,}\\d{1,}\\.?\\d*$")) {
/*
Throws an illegal argument exception if multiple characters of the
sign symbols are detected.
*/
throw new IllegalArgumentException("Invalid number entry. "
+ "Invalid use of sign symbols.");
} else {
// Throws a standard illegal argument exception
throw new IllegalArgumentException("Invalid number entry.");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy