001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.format.number;
018
019import java.math.BigDecimal;
020import java.math.RoundingMode;
021import java.text.DecimalFormat;
022import java.text.NumberFormat;
023import java.text.ParseException;
024import java.util.Currency;
025import java.util.Locale;
026
027/**
028 * A BigDecimal formatter for number values in currency style.
029 *
030 * <p>Delegates to {@link java.text.NumberFormat#getCurrencyInstance(Locale)}.
031 * Configures BigDecimal parsing so there is no loss of precision.
032 * Can apply a specified {@link java.math.RoundingMode} to parsed values.
033 *
034 * @author Keith Donald
035 * @author Juergen Hoeller
036 * @since 4.2
037 * @see #setLenient
038 * @see #setRoundingMode
039 */
040public class CurrencyStyleFormatter extends AbstractNumberFormatter {
041
042        private int fractionDigits = 2;
043
044        private RoundingMode roundingMode;
045
046        private Currency currency;
047
048        private String pattern;
049
050
051        /**
052         * Specify the desired number of fraction digits.
053         * Default is 2.
054         */
055        public void setFractionDigits(int fractionDigits) {
056                this.fractionDigits = fractionDigits;
057        }
058
059        /**
060         * Specify the rounding mode to use for decimal parsing.
061         * Default is {@link java.math.RoundingMode#UNNECESSARY}.
062         */
063        public void setRoundingMode(RoundingMode roundingMode) {
064                this.roundingMode = roundingMode;
065        }
066
067        /**
068         * Specify the currency, if known.
069         */
070        public void setCurrency(Currency currency) {
071                this.currency = currency;
072        }
073
074        /**
075         * Specify the pattern to use to format number values.
076         * If not specified, the default DecimalFormat pattern is used.
077         * @see java.text.DecimalFormat#applyPattern(String)
078         */
079        public void setPattern(String pattern) {
080                this.pattern = pattern;
081        }
082
083
084        @Override
085        public BigDecimal parse(String text, Locale locale) throws ParseException {
086                BigDecimal decimal = (BigDecimal) super.parse(text, locale);
087                if (decimal != null) {
088                        if (this.roundingMode != null) {
089                                decimal = decimal.setScale(this.fractionDigits, this.roundingMode);
090                        }
091                        else {
092                                decimal = decimal.setScale(this.fractionDigits);
093                        }
094                }
095                return decimal;
096        }
097
098        @Override
099        protected NumberFormat getNumberFormat(Locale locale) {
100                DecimalFormat format = (DecimalFormat) NumberFormat.getCurrencyInstance(locale);
101                format.setParseBigDecimal(true);
102                format.setMaximumFractionDigits(this.fractionDigits);
103                format.setMinimumFractionDigits(this.fractionDigits);
104                if (this.roundingMode != null) {
105                        format.setRoundingMode(this.roundingMode);
106                }
107                if (this.currency != null) {
108                        format.setCurrency(this.currency);
109                }
110                if (this.pattern != null) {
111                        format.applyPattern(this.pattern);
112                }
113                return format;
114        }
115
116}