From c0140ee1ee8673ea015b3037aaf88b5f9f1fc858 Mon Sep 17 00:00:00 2001 From: Werner Keil Date: Wed, 22 Jul 2020 00:18:21 +0200 Subject: [PATCH] Update Release --- pom.xml | 10 +- ...efaultMonetaryConversionsSingletonSpi.java | 2 +- .../convert/ECBHistoric90RateProvider.java | 2 +- .../javamoney/moneta/internal/JDKObjects.java | 38 ---- .../org/javamoney/moneta/spi/MoneyUtils.java | 57 ++---- .../moneta/spi/format/AmountNumberToken.java | 184 +++++++----------- .../moneta/spi/format/CurrencyToken.java | 2 +- .../moneta/spi/format/FormatToken.java | 2 +- .../moneta/format/MonetaryFormatsTest.java | 5 +- 9 files changed, 95 insertions(+), 207 deletions(-) delete mode 100644 src/main/java/org/javamoney/moneta/internal/JDKObjects.java diff --git a/pom.xml b/pom.xml index 606f4f8..89322b5 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ moneta-bp bundle - 1.4.1-SNAPSHOT + 1.4.1 Moneta (JSR 354 RI) for Java 7 JSR 354 provides an API for representing, transporting, and performing comprehensive calculations with @@ -53,7 +53,7 @@ Travis-CI - https://travis-ci.org/JavaMoney/javamoney-moneta-bp + https://travis-ci.org/JavaMoney/jsr354-ri-bp @@ -62,10 +62,10 @@ - scm:git:https://github.com/JavaMoney/javamoney-moneta-bp.git + scm:git:https://github.com/JavaMoney/jsr354-ri-bp.git master - scm:git:https://github.com/JavaMoney/javamoney-moneta-bp.git - https://github.com/JavaMoney/javamoney-moneta-bp + scm:git:https://github.com/JavaMoney/jsr354-ri-bp.git + https://github.com/JavaMoney/jsr354-ri-bp diff --git a/src/main/java/org/javamoney/moneta/convert/DefaultMonetaryConversionsSingletonSpi.java b/src/main/java/org/javamoney/moneta/convert/DefaultMonetaryConversionsSingletonSpi.java index 1a82b66..9811726 100644 --- a/src/main/java/org/javamoney/moneta/convert/DefaultMonetaryConversionsSingletonSpi.java +++ b/src/main/java/org/javamoney/moneta/convert/DefaultMonetaryConversionsSingletonSpi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Anatole Tresch, Werner Keil and others by the @author tag. + * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of diff --git a/src/main/java/org/javamoney/moneta/convert/ECBHistoric90RateProvider.java b/src/main/java/org/javamoney/moneta/convert/ECBHistoric90RateProvider.java index ebfa29a..b9d3e3a 100644 --- a/src/main/java/org/javamoney/moneta/convert/ECBHistoric90RateProvider.java +++ b/src/main/java/org/javamoney/moneta/convert/ECBHistoric90RateProvider.java @@ -31,7 +31,7 @@ * The default date is yesterday or the most recent day of week. To uses exchange rate from a specific date, you can use this way: * CurrencyUnit termCurrency = ...; * LocalDate localDate = ...; - * ConversionQuery conversionQuery = ConversionQueryBuilder.of().setTermCurrency(euro).set(localDate).build();v + * ConversionQuery conversionQuery = ConversionQueryBuilder.of().setTermCurrency(euro).setTimestamp(localDate).build();v * CurrencyConversion currencyConversion = provider.getCurrencyConversion(conversionQuery); * MonetaryAmount money = ...; * MonetaryAmount result = currencyConversion.apply(money); diff --git a/src/main/java/org/javamoney/moneta/internal/JDKObjects.java b/src/main/java/org/javamoney/moneta/internal/JDKObjects.java deleted file mode 100644 index 9f73558..0000000 --- a/src/main/java/org/javamoney/moneta/internal/JDKObjects.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (c) 2020, Werner Keil and others by the @author tag. - - Licensed under the Apache License, Version 2.0 (the "License"); you may not - use this file except in compliance with the License. You may obtain a copy of - the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - License for the specific language governing permissions and limitations under - the License. - */ -package org.javamoney.moneta.internal; - -/** - * This is a drop-in-replacement for some convenience methods like nonNull added to the - * Objects class in Java 8 or beyond. - */ -public class JDKObjects { - /** - * JDK Drop-in-replacement - * @since 1.4.1 - */ - public static boolean nonNull(Object obj) { - return obj != null; - } - - /** - * JDK Drop-in-replacement - * @since 1.4.1 - */ - public static boolean isNull(Object obj) { - return obj == null; - } -} diff --git a/src/main/java/org/javamoney/moneta/spi/MoneyUtils.java b/src/main/java/org/javamoney/moneta/spi/MoneyUtils.java index d8e3d82..c687380 100644 --- a/src/main/java/org/javamoney/moneta/spi/MoneyUtils.java +++ b/src/main/java/org/javamoney/moneta/spi/MoneyUtils.java @@ -1,5 +1,5 @@ /* - Copyright (c) 2012, 2020, Werner Keil, Otavio Santana and others by the @author tag. + Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of @@ -15,22 +15,16 @@ */ package org.javamoney.moneta.spi; -import org.javamoney.moneta.internal.JDKObjects; - import javax.money.CurrencyUnit; import javax.money.MonetaryAmount; import javax.money.MonetaryContext; import javax.money.MonetaryException; - import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; +import java.util.Objects; import java.util.logging.Logger; -import static java.math.RoundingMode.HALF_EVEN; -import static java.util.Objects.requireNonNull; -import static java.util.logging.Level.FINEST; - /** * Platform RI: This utility class simplifies implementing {@link MonetaryAmount}, * by providing the common functionality. The different explicitly typed methods @@ -40,17 +34,13 @@ * implement {@link MonetaryAmount} directly. * * @author Anatole Tresch - * @author Werner Keil */ public final class MoneyUtils { - + /** + * The logger used. + */ private static final Logger LOG = Logger.getLogger(MoneyUtils.class.getName()); - public static final String NBSP_STRING = "\u00A0"; - public static final String NNBSP_STRING = "\u202F"; - public static final char NBSP = NBSP_STRING.charAt(0); - public static final char NNBSP = NNBSP_STRING.charAt(0); - private MoneyUtils() { } @@ -104,18 +94,13 @@ public static BigDecimal getBigDecimal(Number num) { * @return the corresponding {@link BigDecimal} */ public static BigDecimal getBigDecimal(Number num, MonetaryContext moneyContext) { - BigDecimal bd = getBigDecimal(num); - if (JDKObjects.nonNull(moneyContext)) { - MathContext mc = getMathContext(moneyContext, HALF_EVEN); + BigDecimal bd = getBigDecimal(num); + if (moneyContext!=null) { + MathContext mc = getMathContext(moneyContext, RoundingMode.HALF_EVEN); bd = new BigDecimal(bd.toString(), mc); - int maxScale = moneyContext.getMaxScale(); - if (maxScale > 0) { - if (bd.scale() > maxScale) { - if (LOG.isLoggable(FINEST)) { - LOG.log(FINEST, "The number scale is " + bd.scale() + " but Max Scale is " + maxScale); - } - bd = bd.setScale(maxScale, mc.getRoundingMode()); - } + if (moneyContext.getMaxScale() > 0) { + LOG.fine(String.format("Got Max Scale %s", moneyContext.getMaxScale())); + bd = bd.setScale(moneyContext.getMaxScale(), mc.getRoundingMode()); } } return bd; @@ -131,12 +116,15 @@ public static BigDecimal getBigDecimal(Number num, MonetaryContext moneyContext) */ public static MathContext getMathContext(MonetaryContext monetaryContext, RoundingMode defaultMode) { MathContext ctx = monetaryContext.get(MathContext.class); - if (JDKObjects.nonNull(ctx)) { + if (ctx!=null) { return ctx; } RoundingMode roundingMode = monetaryContext.get(RoundingMode.class); if (roundingMode == null) { - roundingMode = HALF_EVEN; + roundingMode = defaultMode; + } + if (roundingMode == null) { + roundingMode = RoundingMode.HALF_EVEN; } return new MathContext(monetaryContext.getPrecision(), roundingMode); } @@ -151,9 +139,9 @@ public static MathContext getMathContext(MonetaryContext monetaryContext, Roundi * {@link CurrencyUnit#getCurrencyCode()}). */ public static void checkAmountParameter(MonetaryAmount amount, CurrencyUnit currencyUnit) { - requireNonNull(amount, "Amount must not be null."); + Objects.requireNonNull(amount, "Amount must not be null."); final CurrencyUnit amountCurrency = amount.getCurrency(); - if (!currencyUnit.getCurrencyCode().equals(amountCurrency.getCurrencyCode())) { + if (!(currencyUnit.getCurrencyCode().equals(amountCurrency.getCurrencyCode()))) { throw new MonetaryException("Currency mismatch: " + currencyUnit + '/' + amountCurrency); } } @@ -165,14 +153,7 @@ public static void checkAmountParameter(MonetaryAmount amount, CurrencyUnit curr * @throws IllegalArgumentException If the number is null */ public static void checkNumberParameter(Number number) { - requireNonNull(number, "Number is required."); + Objects.requireNonNull(number, "Number is required."); } - /** - * Replaces the non-breaking space character U+00A0 and Narrow non-breaking space U+202F from the string with usual space. - * https://en.wikipedia.org/wiki/Non-breaking_space} - */ - public static String replaceNbspWithSpace(String s) { - return s.replace(NBSP, ' ').replace(NNBSP, ' '); - } } diff --git a/src/main/java/org/javamoney/moneta/spi/format/AmountNumberToken.java b/src/main/java/org/javamoney/moneta/spi/format/AmountNumberToken.java index f57e034..6d33158 100644 --- a/src/main/java/org/javamoney/moneta/spi/format/AmountNumberToken.java +++ b/src/main/java/org/javamoney/moneta/spi/format/AmountNumberToken.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Werner Keil and others by the @author tag. + * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -15,24 +15,18 @@ */ package org.javamoney.moneta.spi.format; -import org.javamoney.moneta.internal.JDKObjects; -import org.javamoney.moneta.spi.MoneyUtils; +import org.javamoney.moneta.format.AmountFormatParams; -import javax.money.MonetaryAmount; -import javax.money.format.AmountFormatContext; -import javax.money.format.MonetaryParseException; import java.io.IOException; import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; -import java.text.ParsePosition; import java.util.Locale; import java.util.logging.Logger; -import static java.util.Objects.requireNonNull; -import static org.javamoney.moneta.format.AmountFormatParams.GROUPING_GROUPING_SEPARATORS; -import static org.javamoney.moneta.format.AmountFormatParams.GROUPING_SIZES; -import static org.javamoney.moneta.spi.MoneyUtils.replaceNbspWithSpace; +import javax.money.MonetaryAmount; +import javax.money.format.AmountFormatContext; +import javax.money.format.MonetaryParseException; /** * {@link FormatToken} which allows to format a {@link MonetaryAmount} type. @@ -43,47 +37,40 @@ final class AmountNumberToken implements FormatToken { private final AmountFormatContext amountFormatContext; - private final String partialNumberPattern; + private String partialNumberPattern; private DecimalFormat parseFormat; private DecimalFormat formatFormat; private StringGrouper numberGroup; - AmountNumberToken(AmountFormatContext amountFormatContext, String partialNumberPattern) { - requireNonNull(amountFormatContext, "amountFormatContext is required."); - requireNonNull(partialNumberPattern, "partialNumberPattern is required."); + public AmountNumberToken(AmountFormatContext amountFormatContext, String partialNumberPattern) { this.amountFormatContext = amountFormatContext; - this.partialNumberPattern = replaceNbspWithSpace(partialNumberPattern); + if(amountFormatContext==null) { + throw new IllegalArgumentException( + "amountFormatContext is required."); + } + this.partialNumberPattern = partialNumberPattern; initDecimalFormats(); } private void initDecimalFormats() { - Locale locale = amountFormatContext.get(Locale.class); - formatFormat = (DecimalFormat) DecimalFormat.getInstance(locale); - formatFormat.applyPattern(MoneyUtils.replaceNbspWithSpace(formatFormat.toPattern())); - parseFormat = (DecimalFormat) formatFormat.clone(); + formatFormat = (DecimalFormat) DecimalFormat.getInstance(amountFormatContext.get(Locale.class)); + parseFormat = (DecimalFormat) DecimalFormat.getInstance(amountFormatContext.get(Locale.class)); DecimalFormatSymbols syms = amountFormatContext.get(DecimalFormatSymbols.class); - if (JDKObjects.nonNull(syms)) { - syms = (DecimalFormatSymbols) syms.clone(); - } else { - syms = formatFormat.getDecimalFormatSymbols(); - } - fixThousandsSeparatorWithSpace(syms); - formatFormat.setDecimalFormatSymbols(syms); - parseFormat.setDecimalFormatSymbols(syms); - - formatFormat.applyPattern(partialNumberPattern); - parseFormat.applyPattern(partialNumberPattern.trim()); - } - - private void fixThousandsSeparatorWithSpace(DecimalFormatSymbols symbols) { - if(Character.isSpaceChar(formatFormat.getDecimalFormatSymbols().getGroupingSeparator())){ - symbols.setGroupingSeparator(' '); - } - if(Character.isWhitespace(formatFormat.getDecimalFormatSymbols().getDecimalSeparator())){ - symbols.setDecimalSeparator(' '); + if (syms!=null) { + formatFormat.setDecimalFormatSymbols(syms); + parseFormat.setDecimalFormatSymbols(syms); } - if(Character.isWhitespace(formatFormat.getDecimalFormatSymbols().getMonetaryDecimalSeparator())){ - symbols.setMonetaryDecimalSeparator(' '); + formatFormat.applyPattern(this.partialNumberPattern); + parseFormat.applyPattern(this.partialNumberPattern.trim()); + // Fix for https://github.com/JavaMoney/jsr354-ri/issues/151 + if ("BG".equals(amountFormatContext.getLocale().getCountry())) { + formatFormat.setGroupingSize(3); + formatFormat.setGroupingUsed(true); + syms = formatFormat.getDecimalFormatSymbols(); + syms.setDecimalSeparator(','); + syms.setGroupingSeparator(' '); + formatFormat.setDecimalFormatSymbols(syms); + parseFormat.setDecimalFormatSymbols(syms); } } @@ -103,34 +90,40 @@ public AmountFormatContext getAmountFormatContext() { * @return the number pattern used, never {@code null}. */ public String getNumberPattern() { - return partialNumberPattern; + return this.partialNumberPattern; } @Override public void print(Appendable appendable, MonetaryAmount amount) throws IOException { - int[] groupSizes = amountFormatContext.get(GROUPING_SIZES, int[].class); - if (groupSizes == null || groupSizes.length == 0) { - String preformattedValue = formatFormat.format(amount.getNumber().numberValue(BigDecimal.class)); - appendable.append(preformattedValue); + if (amountFormatContext.get(AmountFormatParams.GROUPING_SIZES, int[].class) == null || + amountFormatContext.get(AmountFormatParams.GROUPING_SIZES, int[].class).length == 0) { + appendable.append(this.formatFormat.format(amount.getNumber() + .numberValue(BigDecimal.class))); return; } - formatFormat.setGroupingUsed(false); - String preformattedValue = formatFormat.format(amount.getNumber().numberValue(BigDecimal.class)); - String[] numberParts = splitNumberParts(formatFormat, preformattedValue); + this.formatFormat.setGroupingUsed(false); + String preformattedValue = this.formatFormat.format(amount.getNumber() + .numberValue(BigDecimal.class)); + String[] numberParts = splitNumberParts(this.formatFormat, + preformattedValue); if (numberParts.length != 2) { appendable.append(preformattedValue); } else { - if (JDKObjects.isNull(numberGroup)) { - char[] groupChars = amountFormatContext.get(GROUPING_GROUPING_SEPARATORS, char[].class); + if (numberGroup==null) { + char[] groupChars = amountFormatContext.get(AmountFormatParams.GROUPING_GROUPING_SEPARATORS, char[].class); if (groupChars == null || groupChars.length == 0) { - char groupingSeparator = formatFormat.getDecimalFormatSymbols().getGroupingSeparator(); - groupChars = new char[]{groupingSeparator}; + groupChars = new char[]{this.formatFormat + .getDecimalFormatSymbols().getGroupingSeparator()}; + } + int[] groupSizes = amountFormatContext.get(AmountFormatParams.GROUPING_SIZES, int[].class); + if (groupSizes == null) { + groupSizes = new int[0]; } numberGroup = new StringGrouper(groupChars, groupSizes); } preformattedValue = numberGroup.group(numberParts[0]) - + formatFormat.getDecimalFormatSymbols() + + this.formatFormat.getDecimalFormatSymbols() .getDecimalSeparator() + numberParts[1]; appendable.append(preformattedValue); } @@ -138,21 +131,20 @@ public void print(Appendable appendable, MonetaryAmount amount) private String[] splitNumberParts(DecimalFormat format, String preformattedValue) { - char decimalSeparator = format.getDecimalFormatSymbols().getDecimalSeparator(); - int index = preformattedValue.indexOf(decimalSeparator); + int index = preformattedValue.indexOf(format.getDecimalFormatSymbols() + .getDecimalSeparator()); if (index < 0) { return new String[]{preformattedValue}; } - String beforeSeparator = preformattedValue.substring(0, index); - String afterSeparator = preformattedValue.substring(index + 1); - return new String[]{beforeSeparator, afterSeparator}; + return new String[]{preformattedValue.substring(0, index), + preformattedValue.substring(index + 1)}; } @Override public void parse(ParseContext context) throws MonetaryParseException { - context.skipWhitespace(); - if (!context.isFullyParsed()) { - parseToken(context); + String token = context.lookupNextToken(); + if (token!=null && !context.isComplete()) { + parseToken(context, token); if (context.hasError()) { throw new MonetaryParseException(context.getErrorMessage(), context.getInput(), context.getIndex()); } @@ -162,65 +154,19 @@ public void parse(ParseContext context) throws MonetaryParseException { } } - private void parseToken(ParseContext context) { - ParsePosition pos = new ParsePosition(context.getIndex()); - String consumedInput = context.getInput().toString(); - - // Check for amount with currenccy, so we only parse the amount part... - int[] range = evalNumberRange(consumedInput); // 0: firstDigit, 1: lastDigit - if(range[0]<0){ - context.setError(); - context.setErrorIndex(0); - context.setErrorMessage("No digits found: \"" + context.getOriginalInput() + "\""); - return; - } - consumedInput = consumedInput.substring(0, range[1]+1); - String input = consumedInput.substring(0, range[0]) + // any literal part - consumedInput.substring(range[0]) // number part, without any spaces. - .replace(" ", "") - .replace(MoneyUtils.NBSP_STRING, "") - .replace(MoneyUtils.NNBSP_STRING, ""); - pos = new ParsePosition(0); - Number number = parseFormat.parse(input, pos); - if (JDKObjects.nonNull(number)) { - context.setParsedNumber(number); - context.consume(consumedInput); - } else { - Logger.getLogger(getClass().getName()).finest("Could not parse amount from: " + context.getOriginalInput()); - context.setError(); - context.setErrorIndex(pos.getErrorIndex()); - context.setErrorMessage("Unparseable number: \"" + context.getOriginalInput() + "\""); - } - } - - private int[] evalNumberRange(String input) { - int firstDigit = -1; - int lastDigit = -1; - for(int i=0;i0) { - break; - } + private void parseToken(ParseContext context, String token) { + try { + Number number = this.parseFormat.parse(token); + if (number!=null) { + context.setParsedNumber(number); + context.consume(token); } + } catch (Exception e) { + Logger.getLogger(getClass().getName()).finest( + "Could not parse amount from: " + token); + context.setError(); + context.setErrorMessage(e.getMessage()); } - return new int[]{firstDigit, lastDigit}; } - @Override - public String toString() { - Locale locale = amountFormatContext.getLocale(); - return "AmountNumberToken [locale=" + locale + ", partialNumberPattern=" + partialNumberPattern + ']'; - } } diff --git a/src/main/java/org/javamoney/moneta/spi/format/CurrencyToken.java b/src/main/java/org/javamoney/moneta/spi/format/CurrencyToken.java index feb6424..d5a41c9 100644 --- a/src/main/java/org/javamoney/moneta/spi/format/CurrencyToken.java +++ b/src/main/java/org/javamoney/moneta/spi/format/CurrencyToken.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Anatole Tresch, Werner Keil and others by the @author tag. + * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of diff --git a/src/main/java/org/javamoney/moneta/spi/format/FormatToken.java b/src/main/java/org/javamoney/moneta/spi/format/FormatToken.java index 1ac710a..da93a78 100644 --- a/src/main/java/org/javamoney/moneta/spi/format/FormatToken.java +++ b/src/main/java/org/javamoney/moneta/spi/format/FormatToken.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Werner Keil and others by the @author tag. + * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of diff --git a/src/test/java/org/javamoney/moneta/format/MonetaryFormatsTest.java b/src/test/java/org/javamoney/moneta/format/MonetaryFormatsTest.java index 0d454da..a2686a2 100644 --- a/src/test/java/org/javamoney/moneta/format/MonetaryFormatsTest.java +++ b/src/test/java/org/javamoney/moneta/format/MonetaryFormatsTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2012, 2019, Werner Keil and others by the @author tag. + * Copyright (c) 2012, 2020, Werner Keil and others by the @author tag. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -121,8 +121,7 @@ public void testParse_INR_en_IN() { @Test public void testFormat_INR_en_IN() { MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(INDIA); - //assertMoneyFormat(format, Money.of(67890000000000L, "INR"), "INR 67,890,000,000,000.00"); - assertMoneyFormat(format, Money.of(67890000000000L, "INR"), "INR 6,78,90,00,00,00,000.00"); //TODO: https://github.com/JavaMoney/jsr354-ri-bp/issues/55 + assertMoneyFormat(format, Money.of(67890000000000L, "INR"), "INR 6,78,90,00,00,00,000.00"); } @Test