001/**
002 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://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, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016package org.javamoney.moneta.spi;
017
018import java.math.BigDecimal;
019import java.math.MathContext;
020import java.math.RoundingMode;
021import java.util.Objects;
022
023import javax.money.NumberValue;
024
025/**
026 * Default implementation of {@link NumberValue} based on {@link BigDecimal}.
027 *
028 * @author Anatole Tresch
029 * @author Werner Keil
030 */
031public final class DefaultNumberValue extends NumberValue {
032
033        /**
034         * serialVersionUID.
035         */
036        private static final long serialVersionUID = 1L;
037        /** The numeric value. */
038        private final Number number;
039
040    /**
041     * The value 1, with a scale of 0.<br>
042     * Backed by {@link BigDecimal#ONE}
043     *
044     * @since  0.8
045     */
046        public static final NumberValue ONE = new DefaultNumberValue(BigDecimal.ONE);
047
048        public DefaultNumberValue(Number number) {
049        this.number = Objects.requireNonNull(number, "Number required");
050    }
051
052        /**
053         * Creates a new instance of {@link NumberValue}, using the given number.
054         *
055         * @param number
056         *            The numeric part, not null.
057         * @return A new instance of {@link NumberValue}.
058         */
059        public static NumberValue of(Number number) {
060                return new DefaultNumberValue(number);
061        }
062
063        /*
064         * (non-Javadoc)
065         * @see javax.money.NumberValue#getNumberType()
066         */
067        @Override
068        public Class<?> getNumberType() {
069                return this.number.getClass();
070        }
071
072        /*
073         * (non-Javadoc)
074         * @see javax.money.NumberValue#getPrecision()
075         */
076        @Override
077        public int getPrecision() {
078                return numberValue(BigDecimal.class).precision();
079        }
080
081        /*
082         * (non-Javadoc)
083         * @see javax.money.NumberValue#getScale()
084         */
085        @Override
086        public int getScale() {
087                return ConvertBigDecimal.of(number).scale();
088        }
089
090        /*
091         * (non-Javadoc)
092         * @see javax.money.NumberValue#getIntValue()
093         */
094        @Override
095        public int intValue() {
096                return this.number.intValue();
097        }
098
099        /*
100         * (non-Javadoc)
101         * @see javax.money.NumberValue#getIntValueExact()
102         */
103        @Override
104        public int intValueExact() {
105                return ConvertBigDecimal.of(number).intValueExact();
106        }
107
108        /*
109         * (non-Javadoc)
110         * @see javax.money.NumberValue#getLongValue()
111         */
112        @Override
113        public long longValue() {
114                return this.number.longValue();
115        }
116
117        /*
118         * (non-Javadoc)
119         * @see javax.money.NumberValue#getLongValueExact()
120         */
121        @Override
122        public long longValueExact() {
123                return ConvertBigDecimal.of(number).longValueExact();
124        }
125
126        /*
127         * (non-Javadoc)
128         * @see javax.money.NumberValue#getFloatValue()
129         */
130        @Override
131        public float floatValue() {
132                return this.number.floatValue();
133        }
134
135        /*
136         * (non-Javadoc)
137         * @see javax.money.NumberValue#getDoubleValue()
138         */
139        @Override
140        public double doubleValue() {
141                return this.number.doubleValue();
142        }
143
144        /*
145         * (non-Javadoc)
146         * @see javax.money.NumberValue#getDoubleValueExact()
147         */
148        @Override
149        public double doubleValueExact() {
150                double d = this.number.doubleValue();
151                if (d == Double.NEGATIVE_INFINITY || d == Double.POSITIVE_INFINITY) {
152                        throw new ArithmeticException("Unable to convert to double: "
153                                        + this.number);
154                }
155                return d;
156        }
157
158    /*
159     * (non-Javadoc)
160         * @see javax.money.NumberValue#getAmountFractionNumerator()
161     */
162    @Override
163    public long getAmountFractionNumerator(){
164
165        return ConvertBigDecimal.of(number).setScale(0, RoundingMode.DOWN).longValueExact();
166    }
167
168    /*
169     * (non-Javadoc)
170         * @see javax.money.NumberValue#getAmountFractionDenominator()
171     */
172        @Override
173        public long getAmountFractionDenominator() {
174                BigDecimal value = ConvertBigDecimal.of(number);
175                return value.setScale(value.scale(), RoundingMode.DOWN)
176                                .remainder(BigDecimal.ONE).movePointRight(value.scale())
177                                .longValue();
178        }
179
180        /*
181         * (non-Javadoc)
182         * @see javax.money.NumberValue#getNumberValue(java.lang.Class)
183         */
184        @Override
185        public <T extends Number> T numberValue(Class<T> numberType) {
186                return ConvertNumberValue.of(numberType, number);
187        }
188
189    /*
190     * (non-Javadoc)
191         * @see javax.money.NumberValue#round(java.math.MathContext)
192         */
193    @Override
194    public NumberValue round(MathContext mathContext) {
195        if (this.number instanceof BigDecimal) {
196            return new DefaultNumberValue(((BigDecimal) this.number).round(mathContext));
197        }
198        return new DefaultNumberValue(new BigDecimal(this.number.toString()).round(mathContext));
199    }
200
201    /*
202     * (non-Javadoc)
203     * @see javax.money.NumberValue#numberValueExact(java.lang.Class)
204     */
205    @Override
206        public <T extends Number> T numberValueExact(Class<T> numberType) {
207                return ConvertNumberValue.ofExact(numberType, number);
208        }
209
210        /**
211         * Creates a {@link BigDecimal} from the given {@link Number} doing the valid conversion
212         * depending the type given.
213         *
214         * @param num
215         *            the number type
216         * @return the corresponding {@link BigDecimal}
217         * @deprecated will be removed.
218         */
219        @Deprecated
220        protected static BigDecimal getBigDecimal(Number num) {
221                return ConvertBigDecimal.of(num);
222        }
223
224
225        /*
226         * (non-Javadoc)
227         * @see java.lang.Object#toString()
228         */
229        @Override
230        public String toString() {
231                return String.valueOf(number);
232        }
233
234}