8165466: DecimalFormat percentage format can contain unexpected %
Reviewed-by: okutsu, peytoia
This commit is contained in:
parent
5e84d49af5
commit
f1f59c6623
jdk
src/java.base/share/classes/java/text
test/java/text/Format/DecimalFormat
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.
|
* Decimal : min = 0. max = 3.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void checkAndSetFastPathStatus() {
|
private boolean checkAndSetFastPathStatus() {
|
||||||
|
|
||||||
boolean fastPathWasOn = isFastPath;
|
boolean fastPathWasOn = isFastPath;
|
||||||
|
|
||||||
@ -998,12 +998,27 @@ public class DecimalFormat extends NumberFormat {
|
|||||||
} else
|
} else
|
||||||
isFastPath = false;
|
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
|
// Since some instance properties may have changed while still falling
|
||||||
// in the fast-path case, we need to reinitialize fastPathData anyway.
|
// in the fast-path case, we need to reinitialize fastPathData anyway.
|
||||||
if (isFastPath) {
|
if (isFastPath) {
|
||||||
// We need to instantiate fastPathData if not already done.
|
// We need to instantiate fastPathData if not already done.
|
||||||
if (fastPathData == null)
|
if (fastPathData == null) {
|
||||||
fastPathData = new FastPathData();
|
fastPathData = new FastPathData();
|
||||||
|
}
|
||||||
|
|
||||||
// Sets up the locale specific constants used when formatting.
|
// Sets up the locale specific constants used when formatting.
|
||||||
// '0' is our default representation of zero.
|
// '0' is our default representation of zero.
|
||||||
@ -1011,22 +1026,27 @@ public class DecimalFormat extends NumberFormat {
|
|||||||
fastPathData.groupingChar = symbols.getGroupingSeparator();
|
fastPathData.groupingChar = symbols.getGroupingSeparator();
|
||||||
|
|
||||||
// Sets up fractional constants related to currency/decimal pattern.
|
// Sets up fractional constants related to currency/decimal pattern.
|
||||||
fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999;
|
fastPathData.fractionalMaxIntBound = (isCurrencyFormat)
|
||||||
fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d;
|
? 99 : 999;
|
||||||
|
fastPathData.fractionalScaleFactor = (isCurrencyFormat)
|
||||||
|
? 100.0d : 1000.0d;
|
||||||
|
|
||||||
// Records the need for adding prefix or suffix
|
// Records the need for adding prefix or suffix
|
||||||
fastPathData.positiveAffixesRequired =
|
fastPathData.positiveAffixesRequired
|
||||||
(positivePrefix.length() != 0) || (positiveSuffix.length() != 0);
|
= (positivePrefix.length() != 0)
|
||||||
fastPathData.negativeAffixesRequired =
|
|| (positiveSuffix.length() != 0);
|
||||||
(negativePrefix.length() != 0) || (negativeSuffix.length() != 0);
|
fastPathData.negativeAffixesRequired
|
||||||
|
= (negativePrefix.length() != 0)
|
||||||
|
|| (negativeSuffix.length() != 0);
|
||||||
|
|
||||||
// Creates a cached char container for result, with max possible size.
|
// Creates a cached char container for result, with max possible size.
|
||||||
int maxNbIntegralDigits = 10;
|
int maxNbIntegralDigits = 10;
|
||||||
int maxNbGroups = 3;
|
int maxNbGroups = 3;
|
||||||
int containerSize =
|
int containerSize
|
||||||
Math.max(positivePrefix.length(), negativePrefix.length()) +
|
= Math.max(positivePrefix.length(), negativePrefix.length())
|
||||||
maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits +
|
+ maxNbIntegralDigits + maxNbGroups + 1
|
||||||
Math.max(positiveSuffix.length(), negativeSuffix.length());
|
+ maximumFractionDigits
|
||||||
|
+ Math.max(positiveSuffix.length(), negativeSuffix.length());
|
||||||
|
|
||||||
fastPathData.fastPathContainer = new char[containerSize];
|
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 fixed index positions for integral and fractional digits.
|
||||||
// Sets up decimal point in cached result container.
|
// Sets up decimal point in cached result container.
|
||||||
int longestPrefixLength =
|
int longestPrefixLength
|
||||||
Math.max(positivePrefix.length(), negativePrefix.length());
|
= Math.max(positivePrefix.length(),
|
||||||
int decimalPointIndex =
|
negativePrefix.length());
|
||||||
maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
|
int decimalPointIndex
|
||||||
|
= maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
|
||||||
|
|
||||||
fastPathData.integralLastIndex = decimalPointIndex - 1;
|
fastPathData.integralLastIndex = decimalPointIndex - 1;
|
||||||
fastPathData.fractionalFirstIndex = decimalPointIndex + 1;
|
fastPathData.fractionalFirstIndex = decimalPointIndex + 1;
|
||||||
fastPathData.fastPathContainer[decimalPointIndex] =
|
fastPathData.fastPathContainer[decimalPointIndex]
|
||||||
isCurrencyFormat ?
|
= isCurrencyFormat
|
||||||
symbols.getMonetaryDecimalSeparator() :
|
? symbols.getMonetaryDecimalSeparator()
|
||||||
symbols.getDecimalSeparator();
|
: symbols.getDecimalSeparator();
|
||||||
|
|
||||||
} else if (fastPathWasOn) {
|
} else if (fastPathWasOn) {
|
||||||
// Previous state was fast-path and is no more.
|
// Previous state was fast-path and is no more.
|
||||||
@ -1059,8 +1080,6 @@ public class DecimalFormat extends NumberFormat {
|
|||||||
fastPathData.charsPositivePrefix = null;
|
fastPathData.charsPositivePrefix = null;
|
||||||
fastPathData.charsNegativePrefix = 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.
|
* @return the formatted result for {@code d} as a string.
|
||||||
*/
|
*/
|
||||||
String fastFormat(double d) {
|
String fastFormat(double d) {
|
||||||
|
boolean isDataSet = false;
|
||||||
// (Re-)Evaluates fast-path status if needed.
|
// (Re-)Evaluates fast-path status if needed.
|
||||||
if (fastPathCheckNeeded)
|
if (fastPathCheckNeeded) {
|
||||||
checkAndSetFastPathStatus();
|
isDataSet = checkAndSetFastPathStatus();
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFastPath )
|
if (!isFastPath )
|
||||||
// DecimalFormat instance is not in a fast-path state.
|
// DecimalFormat instance is not in a fast-path state.
|
||||||
@ -1580,9 +1601,21 @@ public class DecimalFormat extends NumberFormat {
|
|||||||
if (d > MAX_INT_AS_DOUBLE)
|
if (d > MAX_INT_AS_DOUBLE)
|
||||||
// Filters out values that are outside expected fast-path range
|
// Filters out values that are outside expected fast-path range
|
||||||
return null;
|
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);
|
fastDoubleFormat(d, negative);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Returns a new string from updated fastPathContainer.
|
// Returns a new string from updated fastPathContainer.
|
||||||
return new String(fastPathData.fastPathContainer,
|
return new String(fastPathData.fastPathContainer,
|
||||||
fastPathData.firstUsedIndex,
|
fastPathData.firstUsedIndex,
|
||||||
|
95
jdk/test/java/text/Format/DecimalFormat/Bug8165466.java
Normal file
95
jdk/test/java/text/Format/DecimalFormat/Bug8165466.java
Normal file
@ -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
|
||||||
|
+ "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user