diff --git a/src/share/classes/java/text/DecimalFormat.java b/src/share/classes/java/text/DecimalFormat.java index a0020ba12a34bc5d188f50f23c092e025c75223a..2b30a75301e8020c51ca3dacb56405e757c7eac5 100644 --- a/src/share/classes/java/text/DecimalFormat.java +++ b/src/share/classes/java/text/DecimalFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -968,7 +968,7 @@ public class DecimalFormat extends NumberFormat { * Decimal : min = 0. max = 3. * */ - private void checkAndSetFastPathStatus() { + private boolean checkAndSetFastPathStatus() { boolean fastPathWasOn = isFastPath; @@ -998,12 +998,27 @@ public class DecimalFormat extends NumberFormat { } else isFastPath = false; + resetFastPathData(fastPathWasOn); + fastPathCheckNeeded = false; + + /* + * Returns true after successfully checking the fast path condition and + * setting the fast path data. The return value is used by the + * fastFormat() method to decide whether to call the resetFastPathData + * method to reinitialize fast path data or is it already initialized + * in this method. + */ + return true; + } + + private void resetFastPathData(boolean fastPathWasOn) { // Since some instance properties may have changed while still falling // in the fast-path case, we need to reinitialize fastPathData anyway. if (isFastPath) { // We need to instantiate fastPathData if not already done. - if (fastPathData == null) + if (fastPathData == null) { fastPathData = new FastPathData(); + } // Sets up the locale specific constants used when formatting. // '0' is our default representation of zero. @@ -1011,22 +1026,27 @@ public class DecimalFormat extends NumberFormat { fastPathData.groupingChar = symbols.getGroupingSeparator(); // Sets up fractional constants related to currency/decimal pattern. - fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999; - fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d; + fastPathData.fractionalMaxIntBound = (isCurrencyFormat) + ? 99 : 999; + fastPathData.fractionalScaleFactor = (isCurrencyFormat) + ? 100.0d : 1000.0d; // Records the need for adding prefix or suffix - fastPathData.positiveAffixesRequired = - (positivePrefix.length() != 0) || (positiveSuffix.length() != 0); - fastPathData.negativeAffixesRequired = - (negativePrefix.length() != 0) || (negativeSuffix.length() != 0); + fastPathData.positiveAffixesRequired + = (positivePrefix.length() != 0) + || (positiveSuffix.length() != 0); + fastPathData.negativeAffixesRequired + = (negativePrefix.length() != 0) + || (negativeSuffix.length() != 0); // Creates a cached char container for result, with max possible size. int maxNbIntegralDigits = 10; int maxNbGroups = 3; - int containerSize = - Math.max(positivePrefix.length(), negativePrefix.length()) + - maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits + - Math.max(positiveSuffix.length(), negativeSuffix.length()); + int containerSize + = Math.max(positivePrefix.length(), negativePrefix.length()) + + maxNbIntegralDigits + maxNbGroups + 1 + + maximumFractionDigits + + Math.max(positiveSuffix.length(), negativeSuffix.length()); fastPathData.fastPathContainer = new char[containerSize]; @@ -1038,17 +1058,18 @@ public class DecimalFormat extends NumberFormat { // Sets up fixed index positions for integral and fractional digits. // Sets up decimal point in cached result container. - int longestPrefixLength = - Math.max(positivePrefix.length(), negativePrefix.length()); - int decimalPointIndex = - maxNbIntegralDigits + maxNbGroups + longestPrefixLength; + int longestPrefixLength + = Math.max(positivePrefix.length(), + negativePrefix.length()); + int decimalPointIndex + = maxNbIntegralDigits + maxNbGroups + longestPrefixLength; - fastPathData.integralLastIndex = decimalPointIndex - 1; + fastPathData.integralLastIndex = decimalPointIndex - 1; fastPathData.fractionalFirstIndex = decimalPointIndex + 1; - fastPathData.fastPathContainer[decimalPointIndex] = - isCurrencyFormat ? - symbols.getMonetaryDecimalSeparator() : - symbols.getDecimalSeparator(); + fastPathData.fastPathContainer[decimalPointIndex] + = isCurrencyFormat + ? symbols.getMonetaryDecimalSeparator() + : symbols.getDecimalSeparator(); } else if (fastPathWasOn) { // Previous state was fast-path and is no more. @@ -1059,8 +1080,6 @@ public class DecimalFormat extends NumberFormat { fastPathData.charsPositivePrefix = null; fastPathData.charsNegativePrefix = null; } - - fastPathCheckNeeded = false; } /** @@ -1554,9 +1573,11 @@ public class DecimalFormat extends NumberFormat { * @return the formatted result for {@code d} as a string. */ String fastFormat(double d) { + boolean isDataSet = false; // (Re-)Evaluates fast-path status if needed. - if (fastPathCheckNeeded) - checkAndSetFastPathStatus(); + if (fastPathCheckNeeded) { + isDataSet = checkAndSetFastPathStatus(); + } if (!isFastPath ) // DecimalFormat instance is not in a fast-path state. @@ -1580,9 +1601,21 @@ public class DecimalFormat extends NumberFormat { if (d > MAX_INT_AS_DOUBLE) // Filters out values that are outside expected fast-path range return null; - else + else { + if (!isDataSet) { + /* + * If the fast path data is not set through + * checkAndSetFastPathStatus() and fulfil the + * fast path conditions then reset the data + * directly through resetFastPathData() + */ + resetFastPathData(isFastPath); + } fastDoubleFormat(d, negative); + } + + // Returns a new string from updated fastPathContainer. return new String(fastPathData.fastPathContainer, fastPathData.firstUsedIndex, diff --git a/test/java/text/Format/DecimalFormat/Bug8165466.java b/test/java/text/Format/DecimalFormat/Bug8165466.java new file mode 100644 index 0000000000000000000000000000000000000000..83873da1a2fb16e142f933828e6d0a0b02775874 --- /dev/null +++ b/test/java/text/Format/DecimalFormat/Bug8165466.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8165466 + * @summary Checks the subsequent function calls of the DecimalFormat.format() + * method in which the minimumFractionDigit is set to 0 and one of + * the format() call include formatting of the number with zero + * fraction value e.g. 0.00, 9.00 + */ + +import java.text.DecimalFormat; +import java.util.Locale; + +public class Bug8165466 { + + public static void main(String[] args) { + DecimalFormat nf = (DecimalFormat) DecimalFormat + .getPercentInstance(Locale.US); + nf.setMaximumFractionDigits(3); + nf.setMinimumFractionDigits(0); + nf.setMultiplier(1); + + double d = 0.005678; + String result = nf.format(d); + if (!result.equals("0.006%")) { + throw new RuntimeException("[Failed while formatting the double" + + " value: " + d + " Expected: 0.006%, Found: " + result + + "]"); + } + + d = 0.00; + result = nf.format(d); + if (!result.equals("0%")) { + throw new RuntimeException("[Failed while formatting the double" + + " value: " + d + " Expected: 0%, Found: " + result + + "]"); + } + + d = 0.005678; + result = nf.format(d); + if (!result.equals("0.006%")) { + throw new RuntimeException("[Failed while formatting the double" + + " value: " + d + " Expected: 0.006%, Found: " + result + + "]"); + } + + //checking with the non zero value + d = 0.005678; + result = nf.format(d); + if (!result.equals("0.006%")) { + throw new RuntimeException("[Failed while formatting the double" + + " value: " + d + " Expected: 0.006%, Found: " + result + + "]"); + } + + d = 9.00; + result = nf.format(d); + if (!result.equals("9%")) { + throw new RuntimeException("[Failed while formatting the double" + + " value: " + d + " Expected: 9%, Found: " + result + + "]"); + } + + d = 0.005678; + result = nf.format(d); + if (!result.equals("0.006%")) { + throw new RuntimeException("[Failed while formatting the double" + + " value: " + d + " Expected: 0.006%, Found: " + result + + "]"); + } + } + +} +