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 javax.money.CurrencyUnit; 019import javax.money.Monetary; 020import javax.money.MonetaryAmount; 021import javax.money.MonetaryAmountFactory; 022import javax.money.MonetaryContext; 023import javax.money.MonetaryContextBuilder; 024import javax.money.MonetaryException; 025 026import java.math.BigDecimal; 027import java.util.Objects; 028 029/** 030 * Basic implementation of {@link javax.money.MonetaryAmountFactory}, which simplifies development of the SPI interface. 031 * 032 * @param <T> the target class implementing {@link javax.money.MonetaryAmount}. 033 * @deprecated Use AbstractAmountFactory 034 */ 035@Deprecated 036public abstract class AbstractAmountBuilder<T extends MonetaryAmount> implements MonetaryAmountFactory<T> { 037 038 /** 039 * The default {@link MonetaryContext} applied, if not set explicitly on creation. 040 */ 041 private final MonetaryContext defaultMonetaryContext = loadDefaultMonetaryContext(); 042 043 /** 044 * The default {@link MonetaryContext} applied, if not set explicitly on creation. 045 */ 046 private final MonetaryContext maxMonetaryContext = loadMaxMonetaryContext(); 047 048 private CurrencyUnit currency; 049 private Number number; 050 private MonetaryContext monetaryContext = defaultMonetaryContext; 051 052 /** 053 * Creates a new instance of {@link MonetaryAmount}, using the default {@link MonetaryContext}. 054 * 055 * @return a {@code MonetaryAmount} combining the numeric value and currency unit. 056 * @throws ArithmeticException If the number exceeds the capabilities of the default {@link MonetaryContext} 057 * used. 058 */ 059 @Override 060 public T create() { 061 if (currency == null) { 062 throw new MonetaryException("Cannot create an instance of '"+this.getAmountType().getName()+"': missing currency."); 063 } 064 if (number == null) { 065 throw new MonetaryException("Cannot create an instance of '"+this.getAmountType().getName()+"': missing number."); 066 } 067 if (monetaryContext == null) { 068 throw new MonetaryException("Cannot create an instance of '"+this.getAmountType().getName()+"': missing context."); 069 } 070 return create(number, currency, monetaryContext); 071 } 072 073 protected abstract T create(Number number, CurrencyUnit currency, MonetaryContext monetaryContext); 074 075 protected abstract MonetaryContext loadDefaultMonetaryContext(); 076 077 protected abstract MonetaryContext loadMaxMonetaryContext(); 078 079 080 /* 081 * (non-Javadoc) 082 * @see javax.money.MonetaryAmountFactory#withCurrency(javax.money.CurrencyUnit) 083 */ 084 @Override 085 public MonetaryAmountFactory<T> setCurrency(CurrencyUnit currency) { 086 Objects.requireNonNull(currency); 087 this.currency = currency; 088 return this; 089 } 090 091 /* 092 * (non-Javadoc) 093 * @see javax.money.MonetaryAmountFactory#with(java.lang.Number) 094 */ 095 @Override 096 public MonetaryAmountFactory<T> setNumber(Number number) { 097 this.number = ConvertBigDecimal.of(number); 098 return this; 099 } 100 101 /* 102 * (non-Javadoc) 103 * @see javax.money.MonetaryAmountFactory#withCurrency(java.lang.String) 104 */ 105 @Override 106 public MonetaryAmountFactory<T> setCurrency(String currencyCode) { 107 this.currency = Monetary.getCurrency(currencyCode); 108 return this; 109 } 110 111 /** 112 * Creates a new instance of {@link javax.money.Monetary}, using the default {@link MonetaryContext}. 113 * 114 * @param number numeric value. 115 * @return a {@code Money} combining the numeric value and currency unit. 116 * @throws ArithmeticException If the number exceeds the capabilities of the default {@link MonetaryContext} 117 * used. 118 * @throws javax.money.UnknownCurrencyException if the currency code can not be resolved to {@link CurrencyUnit}. 119 */ 120 @Override 121 public MonetaryAmountFactory<T> setNumber(double number) { 122 this.number = new BigDecimal(String.valueOf(number)); 123 return this; 124 } 125 126 /* 127 * (non-Javadoc) 128 * @see javax.money.MonetaryAmountFactory#with(long) 129 */ 130 @Override 131 public MonetaryAmountFactory<T> setNumber(long number) { 132 this.number = BigDecimal.valueOf(number); 133 return this; 134 } 135 136 /* 137 * (non-Javadoc) 138 * @see javax.money.MonetaryAmountFactory#with(javax.money.MonetaryContext) 139 */ 140 @Override 141 public MonetaryAmountFactory<T> setContext(MonetaryContext monetaryContext) { 142 Objects.requireNonNull(monetaryContext); 143 int maxScale = getMaximalMonetaryContext().getMaxScale(); 144 if (maxScale != -1 && maxScale < monetaryContext.getMaxScale()) { 145 throw new MonetaryException( 146 "Context exceeds maximal capabilities (scale) of this type: " + monetaryContext); 147 } 148 int precision = getMaximalMonetaryContext().getPrecision(); 149 if (precision != 0 && precision < monetaryContext.getPrecision()) { 150 throw new MonetaryException( 151 "Contexts exceeds maximal capabilities (precision) of this type: " + monetaryContext); 152 } 153 this.monetaryContext = monetaryContext.toBuilder() 154 .setAmountType(getAmountType()).build(); 155 return this; 156 } 157 158 /** 159 * Returns the default {@link MonetaryContext} used, when no {@link MonetaryContext} is 160 * provided. 161 * 162 * @return the default {@link MonetaryContext}, never {@code null}. 163 */ 164 @Override 165 public MonetaryContext getDefaultMonetaryContext() { 166 return defaultMonetaryContext; 167 } 168 169 /** 170 * Returns the maximal {@link MonetaryContext} supported. 171 * 172 * @return the maximal {@link MonetaryContext}, never {@code null}. 173 */ 174 @Override 175 public MonetaryContext getMaximalMonetaryContext() { 176 return maxMonetaryContext; 177 } 178 179 /** 180 * Converts (if necessary) the given {@link MonetaryAmount} to a new {@link MonetaryAmount} 181 * instance, hereby supporting the {@link MonetaryContext} given. 182 * 183 * @param amount the amount to be converted, if necessary. 184 * @return an according Money instance. 185 */ 186 @Override 187 public MonetaryAmountFactory<T> setAmount(MonetaryAmount amount) { 188 this.currency = amount.getCurrency(); 189 this.number = amount.getNumber().numberValue(BigDecimal.class); 190 this.monetaryContext = MonetaryContextBuilder.of(defaultMonetaryContext.getAmountType()) 191 .importContext(amount.getContext()).build(); 192 return this; 193 } 194 195 /** 196 * Creates a {@link BigDecimal} from the given {@link Number} doing the valid conversion 197 * depending the type given. 198 * 199 * @param num the number type 200 * @return the corresponding {@link BigDecimal} 201 * @deprecated will be removed in next release 202 */ 203 @Deprecated 204 protected static BigDecimal getBigDecimal(Number num) { 205 return ConvertBigDecimal.of(num); 206 } 207 208 209}