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
027import org.springframework.lang.Nullable;
028
029/**
030 * A BigDecimal formatter for number values in currency style.
031 *
032 * <p>Delegates to {@link java.text.NumberFormat#getCurrencyInstance(Locale)}.
033 * Configures BigDecimal parsing so there is no loss of precision.
034 * Can apply a specified {@link java.math.RoundingMode} to parsed values.
035 *
036 * @author Keith Donald
037 * @author Juergen Hoeller
038 * @since 4.2
039 * @see #setLenient
040 * @see #setRoundingMode
041 */
042public class CurrencyStyleFormatter extends AbstractNumberFormatter {
043
044        private int fractionDigits = 2;
045
046        @Nullable
047        private RoundingMode roundingMode;
048
049        @Nullable
050        private Currency currency;
051
052        @Nullable
053        private String pattern;
054
055
056        /**
057         * Specify the desired number of fraction digits.
058         * Default is 2.
059         */
060        public void setFractionDigits(int fractionDigits) {
061                this.fractionDigits = fractionDigits;
062        }
063
064        /**
065         * Specify the rounding mode to use for decimal parsing.
066         * Default is {@link java.math.RoundingMode#UNNECESSARY}.
067         */
068        public void setRoundingMode(RoundingMode roundingMode) {
069                this.roundingMode = roundingMode;
070        }
071
072        /**
073         * Specify the currency, if known.
074         */
075        public void setCurrency(Currency currency) {
076                this.currency = currency;
077        }
078
079        /**
080         * Specify the pattern to use to format number values.
081         * If not specified, the default DecimalFormat pattern is used.
082         * @see java.text.DecimalFormat#applyPattern(String)
083         */
084        public void setPattern(String pattern) {
085                this.pattern = pattern;
086        }
087
088
089        @Override
090        public BigDecimal parse(String text, Locale locale) throws ParseException {
091                BigDecimal decimal = (BigDecimal) super.parse(text, locale);
092                if (this.roundingMode != null) {
093                        decimal = decimal.setScale(this.fractionDigits, this.roundingMode);
094                }
095                else {
096                        decimal = decimal.setScale(this.fractionDigits);
097                }
098                return decimal;
099        }
100
101        @Override
102        protected NumberFormat getNumberFormat(Locale locale) {
103                DecimalFormat format = (DecimalFormat) NumberFormat.getCurrencyInstance(locale);
104                format.setParseBigDecimal(true);
105                format.setMaximumFractionDigits(this.fractionDigits);
106                format.setMinimumFractionDigits(this.fractionDigits);
107                if (this.roundingMode != null) {
108                        format.setRoundingMode(this.roundingMode);
109                }
110                if (this.currency != null) {
111                        format.setCurrency(this.currency);
112                }
113                if (this.pattern != null) {
114                        format.applyPattern(this.pattern);
115                }
116                return format;
117        }
118
119}