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.function; 017 018import java.math.BigDecimal; 019import java.math.MathContext; 020import java.math.RoundingMode; 021import java.util.Objects; 022 023import javax.money.MonetaryAmount; 024import javax.money.MonetaryOperator; 025 026import org.javamoney.moneta.RoundedMoney; 027 028/** 029 * This implementation uses a {@link MathContext} to does the rounding operations. The implementation will use the <b>precision</b>, in other words, the total number of digits in a number 030 * The derived class will implements the {@link RoundedMoney} with this rounding monetary operator 031 * <pre> 032 * {@code 033 * 034 * MathContext mathContext = new MathContext(4, RoundingMode.HALF_EVEN); 035 * MonetaryOperator monetaryOperator = PrecisionContextRoundedOperator.of(mathContext); 036 * CurrencyUnit real = Monetary.getCurrency("BRL"); 037 * MonetaryAmount money = Money.of(BigDecimal.valueOf(35.34567), real); 038 * MonetaryAmount result = monetaryOperator.apply(money); // BRL 35.35 039 * 040 * } 041* </pre> 042* Case the parameter in {@link MonetaryOperator#apply(MonetaryAmount)} be null, the apply will return a {@link NullPointerException} 043 * @author Otavio Santana 044 * @see PrecisionContextRoundedOperator#of(MathContext) 045 * @see RoundedMoney 046 * @see MonetaryOperator 047 * @see BigDecimal#precision() 048 */ 049public final class PrecisionContextRoundedOperator implements MonetaryOperator { 050 051 private final MathContext mathContext; 052 053 private PrecisionContextRoundedOperator(MathContext mathContext) { 054 this.mathContext = mathContext; 055 } 056 057 /** 058 * Creates the rounded Operator from mathContext 059 * @param mathContext the math context, not null. 060 * @return the {@link MonetaryOperator} using the {@link MathContext} used in parameter 061 * @throws NullPointerException when the {@link MathContext} is null 062 * @throws IllegalArgumentException when the {@link MathContext#getPrecision()} is lesser than zero 063 * @throws IllegalArgumentException when the mathContext is {@link MathContext#getRoundingMode()} is {@link RoundingMode#UNNECESSARY} 064 * @see MathContext 065 */ 066 public static PrecisionContextRoundedOperator of(MathContext mathContext) { 067 068 Objects.requireNonNull(mathContext); 069 070 if(RoundingMode.UNNECESSARY.equals(mathContext.getRoundingMode())) { 071 throw new IllegalArgumentException("To create the MathContextRoundedOperator you cannot use the RoundingMode.UNNECESSARY on MathContext"); 072 } 073 074 if(mathContext.getPrecision() <= 0) { 075 throw new IllegalArgumentException("To create the MathContextRoundedOperator you cannot use the zero precision on MathContext"); 076 } 077 078 return new PrecisionContextRoundedOperator(mathContext); 079 } 080 081 @Override 082 public MonetaryAmount apply(MonetaryAmount amount) { 083 RoundedMoney roundedMoney = RoundedMoney.from(Objects.requireNonNull(amount)); 084 BigDecimal numberValue = roundedMoney.getNumber().numberValue(BigDecimal.class); 085 BigDecimal numberRounded = numberValue.round(mathContext); 086 return RoundedMoney.of(numberRounded, roundedMoney.getCurrency(), this); 087 } 088 089 public MathContext getMathContext() { 090 return mathContext; 091 } 092 093 @Override 094 public String toString() { 095 return PrecisionContextRoundedOperator.class.getName() + '{' + 096 "mathContext:" + mathContext + '}'; 097 } 098 099}