7003643: [Fmt-Me] MessageFormat.toPattern produces wrong quoted string and subformat modifiers
7008195: [Fmt-Me] Improve MessageFormat.applyPattern performance Reviewed-by: naoto, peytoia
This commit is contained in:
parent
f6993442af
commit
f2bb972af4
@ -423,18 +423,19 @@ public class MessageFormat extends Format {
|
||||
* @exception IllegalArgumentException if the pattern is invalid
|
||||
*/
|
||||
public void applyPattern(String pattern) {
|
||||
StringBuffer[] segments = new StringBuffer[4];
|
||||
for (int i = 0; i < segments.length; ++i) {
|
||||
segments[i] = new StringBuffer();
|
||||
}
|
||||
int part = 0;
|
||||
StringBuilder[] segments = new StringBuilder[4];
|
||||
// Allocate only segments[SEG_RAW] here. The rest are
|
||||
// allocated on demand.
|
||||
segments[SEG_RAW] = new StringBuilder();
|
||||
|
||||
int part = SEG_RAW;
|
||||
int formatNumber = 0;
|
||||
boolean inQuote = false;
|
||||
int braceStack = 0;
|
||||
maxOffset = -1;
|
||||
for (int i = 0; i < pattern.length(); ++i) {
|
||||
char ch = pattern.charAt(i);
|
||||
if (part == 0) {
|
||||
if (part == SEG_RAW) {
|
||||
if (ch == '\'') {
|
||||
if (i + 1 < pattern.length()
|
||||
&& pattern.charAt(i+1) == '\'') {
|
||||
@ -444,43 +445,61 @@ public class MessageFormat extends Format {
|
||||
inQuote = !inQuote;
|
||||
}
|
||||
} else if (ch == '{' && !inQuote) {
|
||||
part = 1;
|
||||
part = SEG_INDEX;
|
||||
if (segments[SEG_INDEX] == null) {
|
||||
segments[SEG_INDEX] = new StringBuilder();
|
||||
}
|
||||
} else {
|
||||
segments[part].append(ch);
|
||||
}
|
||||
} else if (inQuote) { // just copy quotes in parts
|
||||
segments[part].append(ch);
|
||||
if (ch == '\'') {
|
||||
inQuote = false;
|
||||
}
|
||||
} else {
|
||||
switch (ch) {
|
||||
case ',':
|
||||
if (part < 3)
|
||||
part += 1;
|
||||
else
|
||||
segments[part].append(ch);
|
||||
break;
|
||||
case '{':
|
||||
++braceStack;
|
||||
} else {
|
||||
if (inQuote) { // just copy quotes in parts
|
||||
segments[part].append(ch);
|
||||
break;
|
||||
case '}':
|
||||
if (braceStack == 0) {
|
||||
part = 0;
|
||||
makeFormat(i, formatNumber, segments);
|
||||
formatNumber++;
|
||||
} else {
|
||||
--braceStack;
|
||||
segments[part].append(ch);
|
||||
if (ch == '\'') {
|
||||
inQuote = false;
|
||||
}
|
||||
} else {
|
||||
switch (ch) {
|
||||
case ',':
|
||||
if (part < SEG_MODIFIER) {
|
||||
if (segments[++part] == null) {
|
||||
segments[part] = new StringBuilder();
|
||||
}
|
||||
} else {
|
||||
segments[part].append(ch);
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
++braceStack;
|
||||
segments[part].append(ch);
|
||||
break;
|
||||
case '}':
|
||||
if (braceStack == 0) {
|
||||
part = SEG_RAW;
|
||||
makeFormat(i, formatNumber, segments);
|
||||
formatNumber++;
|
||||
// throw away other segments
|
||||
segments[SEG_INDEX] = null;
|
||||
segments[SEG_TYPE] = null;
|
||||
segments[SEG_MODIFIER] = null;
|
||||
} else {
|
||||
--braceStack;
|
||||
segments[part].append(ch);
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
// Skip any leading space chars for SEG_TYPE.
|
||||
if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
|
||||
segments[part].append(ch);
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
inQuote = true;
|
||||
// fall through, so we keep quotes in other parts
|
||||
default:
|
||||
segments[part].append(ch);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
inQuote = true;
|
||||
// fall through, so we keep quotes in other parts
|
||||
default:
|
||||
segments[part].append(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -502,65 +521,57 @@ public class MessageFormat extends Format {
|
||||
public String toPattern() {
|
||||
// later, make this more extensible
|
||||
int lastOffset = 0;
|
||||
StringBuffer result = new StringBuffer();
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i <= maxOffset; ++i) {
|
||||
copyAndFixQuotes(pattern, lastOffset, offsets[i],result);
|
||||
copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
|
||||
lastOffset = offsets[i];
|
||||
result.append('{');
|
||||
result.append(argumentNumbers[i]);
|
||||
if (formats[i] == null) {
|
||||
result.append('{').append(argumentNumbers[i]);
|
||||
Format fmt = formats[i];
|
||||
if (fmt == null) {
|
||||
// do nothing, string format
|
||||
} else if (formats[i] instanceof DecimalFormat) {
|
||||
if (formats[i].equals(NumberFormat.getInstance(locale))) {
|
||||
} else if (fmt instanceof NumberFormat) {
|
||||
if (fmt.equals(NumberFormat.getInstance(locale))) {
|
||||
result.append(",number");
|
||||
} else if (formats[i].equals(NumberFormat.getCurrencyInstance(locale))) {
|
||||
} else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
|
||||
result.append(",number,currency");
|
||||
} else if (formats[i].equals(NumberFormat.getPercentInstance(locale))) {
|
||||
} else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
|
||||
result.append(",number,percent");
|
||||
} else if (formats[i].equals(NumberFormat.getIntegerInstance(locale))) {
|
||||
} else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
|
||||
result.append(",number,integer");
|
||||
} else {
|
||||
result.append(",number," +
|
||||
((DecimalFormat)formats[i]).toPattern());
|
||||
if (fmt instanceof DecimalFormat) {
|
||||
result.append(",number,").append(((DecimalFormat)fmt).toPattern());
|
||||
} else if (fmt instanceof ChoiceFormat) {
|
||||
result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
|
||||
} else {
|
||||
// UNKNOWN
|
||||
}
|
||||
}
|
||||
} else if (formats[i] instanceof SimpleDateFormat) {
|
||||
if (formats[i].equals(DateFormat.getDateInstance(
|
||||
DateFormat.DEFAULT,locale))) {
|
||||
result.append(",date");
|
||||
} else if (formats[i].equals(DateFormat.getDateInstance(
|
||||
DateFormat.SHORT,locale))) {
|
||||
result.append(",date,short");
|
||||
} else if (formats[i].equals(DateFormat.getDateInstance(
|
||||
DateFormat.DEFAULT,locale))) {
|
||||
result.append(",date,medium");
|
||||
} else if (formats[i].equals(DateFormat.getDateInstance(
|
||||
DateFormat.LONG,locale))) {
|
||||
result.append(",date,long");
|
||||
} else if (formats[i].equals(DateFormat.getDateInstance(
|
||||
DateFormat.FULL,locale))) {
|
||||
result.append(",date,full");
|
||||
} else if (formats[i].equals(DateFormat.getTimeInstance(
|
||||
DateFormat.DEFAULT,locale))) {
|
||||
result.append(",time");
|
||||
} else if (formats[i].equals(DateFormat.getTimeInstance(
|
||||
DateFormat.SHORT,locale))) {
|
||||
result.append(",time,short");
|
||||
} else if (formats[i].equals(DateFormat.getTimeInstance(
|
||||
DateFormat.DEFAULT,locale))) {
|
||||
result.append(",time,medium");
|
||||
} else if (formats[i].equals(DateFormat.getTimeInstance(
|
||||
DateFormat.LONG,locale))) {
|
||||
result.append(",time,long");
|
||||
} else if (formats[i].equals(DateFormat.getTimeInstance(
|
||||
DateFormat.FULL,locale))) {
|
||||
result.append(",time,full");
|
||||
} else {
|
||||
result.append(",date,"
|
||||
+ ((SimpleDateFormat)formats[i]).toPattern());
|
||||
} else if (fmt instanceof DateFormat) {
|
||||
int index;
|
||||
for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
|
||||
DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
|
||||
locale);
|
||||
if (fmt.equals(df)) {
|
||||
result.append(",date");
|
||||
break;
|
||||
}
|
||||
df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
|
||||
locale);
|
||||
if (fmt.equals(df)) {
|
||||
result.append(",time");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index >= DATE_TIME_MODIFIERS.length) {
|
||||
if (fmt instanceof SimpleDateFormat) {
|
||||
result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
|
||||
} else {
|
||||
// UNKNOWN
|
||||
}
|
||||
} else if (index != MODIFIER_DEFAULT) {
|
||||
result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
|
||||
}
|
||||
} else if (formats[i] instanceof ChoiceFormat) {
|
||||
result.append(",choice,"
|
||||
+ ((ChoiceFormat)formats[i]).toPattern());
|
||||
} else {
|
||||
//result.append(", unknown");
|
||||
}
|
||||
@ -674,7 +685,7 @@ public class MessageFormat extends Format {
|
||||
*
|
||||
* @param formatElementIndex the index of a format element within the pattern
|
||||
* @param newFormat the format to use for the specified format element
|
||||
* @exception ArrayIndexOutOfBoundsException if formatElementIndex is equal to or
|
||||
* @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
|
||||
* larger than the number of format elements in the pattern string
|
||||
*/
|
||||
public void setFormat(int formatElementIndex, Format newFormat) {
|
||||
@ -968,7 +979,8 @@ public class MessageFormat extends Format {
|
||||
if (patternOffset >= tempLength) {
|
||||
next = source.length();
|
||||
}else{
|
||||
next = source.indexOf( pattern.substring(patternOffset,tempLength), sourceOffset);
|
||||
next = source.indexOf(pattern.substring(patternOffset, tempLength),
|
||||
sourceOffset);
|
||||
}
|
||||
|
||||
if (next < 0) {
|
||||
@ -1222,7 +1234,7 @@ public class MessageFormat extends Format {
|
||||
lastOffset = offsets[i];
|
||||
int argumentNumber = argumentNumbers[i];
|
||||
if (arguments == null || argumentNumber >= arguments.length) {
|
||||
result.append("{" + argumentNumber + "}");
|
||||
result.append('{').append(argumentNumber).append('}');
|
||||
continue;
|
||||
}
|
||||
// int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
|
||||
@ -1334,25 +1346,83 @@ public class MessageFormat extends Format {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[] typeList =
|
||||
{"", "", "number", "", "date", "", "time", "", "choice"};
|
||||
private static final String[] modifierList =
|
||||
{"", "", "currency", "", "percent", "", "integer"};
|
||||
private static final String[] dateModifierList =
|
||||
{"", "", "short", "", "medium", "", "long", "", "full"};
|
||||
// Indices for segments
|
||||
private static final int SEG_RAW = 0;
|
||||
private static final int SEG_INDEX = 1;
|
||||
private static final int SEG_TYPE = 2;
|
||||
private static final int SEG_MODIFIER = 3; // modifier or subformat
|
||||
|
||||
// Indices for type keywords
|
||||
private static final int TYPE_NULL = 0;
|
||||
private static final int TYPE_NUMBER = 1;
|
||||
private static final int TYPE_DATE = 2;
|
||||
private static final int TYPE_TIME = 3;
|
||||
private static final int TYPE_CHOICE = 4;
|
||||
|
||||
private static final String[] TYPE_KEYWORDS = {
|
||||
"",
|
||||
"number",
|
||||
"date",
|
||||
"time",
|
||||
"choice"
|
||||
};
|
||||
|
||||
// Indices for number modifiers
|
||||
private static final int MODIFIER_DEFAULT = 0; // common in number and date-time
|
||||
private static final int MODIFIER_CURRENCY = 1;
|
||||
private static final int MODIFIER_PERCENT = 2;
|
||||
private static final int MODIFIER_INTEGER = 3;
|
||||
|
||||
private static final String[] NUMBER_MODIFIER_KEYWORDS = {
|
||||
"",
|
||||
"currency",
|
||||
"percent",
|
||||
"integer"
|
||||
};
|
||||
|
||||
// Indices for date-time modifiers
|
||||
private static final int MODIFIER_SHORT = 1;
|
||||
private static final int MODIFIER_MEDIUM = 2;
|
||||
private static final int MODIFIER_LONG = 3;
|
||||
private static final int MODIFIER_FULL = 4;
|
||||
|
||||
private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
|
||||
"",
|
||||
"short",
|
||||
"medium",
|
||||
"long",
|
||||
"full"
|
||||
};
|
||||
|
||||
// Date-time style values corresponding to the date-time modifiers.
|
||||
private static final int[] DATE_TIME_MODIFIERS = {
|
||||
DateFormat.DEFAULT,
|
||||
DateFormat.SHORT,
|
||||
DateFormat.MEDIUM,
|
||||
DateFormat.LONG,
|
||||
DateFormat.FULL,
|
||||
};
|
||||
|
||||
private void makeFormat(int position, int offsetNumber,
|
||||
StringBuffer[] segments)
|
||||
StringBuilder[] textSegments)
|
||||
{
|
||||
String[] segments = new String[textSegments.length];
|
||||
for (int i = 0; i < textSegments.length; i++) {
|
||||
StringBuilder oneseg = textSegments[i];
|
||||
segments[i] = (oneseg != null) ? oneseg.toString() : "";
|
||||
}
|
||||
|
||||
// get the argument number
|
||||
int argumentNumber;
|
||||
try {
|
||||
argumentNumber = Integer.parseInt(segments[1].toString()); // always unlocalized!
|
||||
argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("can't parse argument number: " + segments[1]);
|
||||
throw new IllegalArgumentException("can't parse argument number: "
|
||||
+ segments[SEG_INDEX], e);
|
||||
}
|
||||
if (argumentNumber < 0) {
|
||||
throw new IllegalArgumentException("negative argument number: " + argumentNumber);
|
||||
throw new IllegalArgumentException("negative argument number: "
|
||||
+ argumentNumber);
|
||||
}
|
||||
|
||||
// resize format information arrays if necessary
|
||||
@ -1370,120 +1440,129 @@ public class MessageFormat extends Format {
|
||||
}
|
||||
int oldMaxOffset = maxOffset;
|
||||
maxOffset = offsetNumber;
|
||||
offsets[offsetNumber] = segments[0].length();
|
||||
offsets[offsetNumber] = segments[SEG_RAW].length();
|
||||
argumentNumbers[offsetNumber] = argumentNumber;
|
||||
|
||||
// now get the format
|
||||
Format newFormat = null;
|
||||
switch (findKeyword(segments[2].toString(), typeList)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1: case 2:// number
|
||||
switch (findKeyword(segments[3].toString(), modifierList)) {
|
||||
case 0: // default;
|
||||
newFormat = NumberFormat.getInstance(locale);
|
||||
if (segments[SEG_TYPE].length() != 0) {
|
||||
int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
|
||||
switch (type) {
|
||||
case TYPE_NULL:
|
||||
// Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
|
||||
// are treated as "{0}".
|
||||
break;
|
||||
case 1: case 2:// currency
|
||||
newFormat = NumberFormat.getCurrencyInstance(locale);
|
||||
|
||||
case TYPE_NUMBER:
|
||||
switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
|
||||
case MODIFIER_DEFAULT:
|
||||
newFormat = NumberFormat.getInstance(locale);
|
||||
break;
|
||||
case MODIFIER_CURRENCY:
|
||||
newFormat = NumberFormat.getCurrencyInstance(locale);
|
||||
break;
|
||||
case MODIFIER_PERCENT:
|
||||
newFormat = NumberFormat.getPercentInstance(locale);
|
||||
break;
|
||||
case MODIFIER_INTEGER:
|
||||
newFormat = NumberFormat.getIntegerInstance(locale);
|
||||
break;
|
||||
default: // DecimalFormat pattern
|
||||
try {
|
||||
newFormat = new DecimalFormat(segments[SEG_MODIFIER],
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
} catch (IllegalArgumentException e) {
|
||||
maxOffset = oldMaxOffset;
|
||||
throw e;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3: case 4:// percent
|
||||
newFormat = NumberFormat.getPercentInstance(locale);
|
||||
|
||||
case TYPE_DATE:
|
||||
case TYPE_TIME:
|
||||
int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
|
||||
if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
|
||||
if (type == TYPE_DATE) {
|
||||
newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
|
||||
locale);
|
||||
} else {
|
||||
newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
|
||||
locale);
|
||||
}
|
||||
} else {
|
||||
// SimpleDateFormat pattern
|
||||
try {
|
||||
newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
|
||||
} catch (IllegalArgumentException e) {
|
||||
maxOffset = oldMaxOffset;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5: case 6:// integer
|
||||
newFormat = NumberFormat.getIntegerInstance(locale);
|
||||
break;
|
||||
default: // pattern
|
||||
newFormat = new DecimalFormat(segments[3].toString(), DecimalFormatSymbols.getInstance(locale));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3: case 4: // date
|
||||
switch (findKeyword(segments[3].toString(), dateModifierList)) {
|
||||
case 0: // default
|
||||
newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
|
||||
break;
|
||||
case 1: case 2: // short
|
||||
newFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale);
|
||||
break;
|
||||
case 3: case 4: // medium
|
||||
newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
|
||||
break;
|
||||
case 5: case 6: // long
|
||||
newFormat = DateFormat.getDateInstance(DateFormat.LONG, locale);
|
||||
break;
|
||||
case 7: case 8: // full
|
||||
newFormat = DateFormat.getDateInstance(DateFormat.FULL, locale);
|
||||
|
||||
case TYPE_CHOICE:
|
||||
try {
|
||||
// ChoiceFormat pattern
|
||||
newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
|
||||
} catch (Exception e) {
|
||||
maxOffset = oldMaxOffset;
|
||||
throw new IllegalArgumentException("Choice Pattern incorrect: "
|
||||
+ segments[SEG_MODIFIER], e);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
newFormat = new SimpleDateFormat(segments[3].toString(), locale);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 5: case 6:// time
|
||||
switch (findKeyword(segments[3].toString(), dateModifierList)) {
|
||||
case 0: // default
|
||||
newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
|
||||
break;
|
||||
case 1: case 2: // short
|
||||
newFormat = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
|
||||
break;
|
||||
case 3: case 4: // medium
|
||||
newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
|
||||
break;
|
||||
case 5: case 6: // long
|
||||
newFormat = DateFormat.getTimeInstance(DateFormat.LONG, locale);
|
||||
break;
|
||||
case 7: case 8: // full
|
||||
newFormat = DateFormat.getTimeInstance(DateFormat.FULL, locale);
|
||||
break;
|
||||
default:
|
||||
newFormat = new SimpleDateFormat(segments[3].toString(), locale);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 7: case 8:// choice
|
||||
try {
|
||||
newFormat = new ChoiceFormat(segments[3].toString());
|
||||
} catch (Exception e) {
|
||||
maxOffset = oldMaxOffset;
|
||||
throw new IllegalArgumentException(
|
||||
"Choice Pattern incorrect");
|
||||
throw new IllegalArgumentException("unknown format type: " +
|
||||
segments[SEG_TYPE]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
maxOffset = oldMaxOffset;
|
||||
throw new IllegalArgumentException("unknown format type: " +
|
||||
segments[2].toString());
|
||||
}
|
||||
formats[offsetNumber] = newFormat;
|
||||
segments[1].setLength(0); // throw away other segments
|
||||
segments[2].setLength(0);
|
||||
segments[3].setLength(0);
|
||||
}
|
||||
|
||||
private static final int findKeyword(String s, String[] list) {
|
||||
s = s.trim().toLowerCase();
|
||||
for (int i = 0; i < list.length; ++i) {
|
||||
if (s.equals(list[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
// Try trimmed lowercase.
|
||||
String ls = s.trim().toLowerCase(Locale.ROOT);
|
||||
if (ls != s) {
|
||||
for (int i = 0; i < list.length; ++i) {
|
||||
if (ls.equals(list[i]))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static final void copyAndFixQuotes(
|
||||
String source, int start, int end, StringBuffer target) {
|
||||
private static final void copyAndFixQuotes(String source, int start, int end,
|
||||
StringBuilder target) {
|
||||
boolean quoted = false;
|
||||
|
||||
for (int i = start; i < end; ++i) {
|
||||
char ch = source.charAt(i);
|
||||
if (ch == '{') {
|
||||
target.append("'{'");
|
||||
} else if (ch == '}') {
|
||||
target.append("'}'");
|
||||
if (!quoted) {
|
||||
target.append('\'');
|
||||
quoted = true;
|
||||
}
|
||||
target.append(ch);
|
||||
} else if (ch == '\'') {
|
||||
target.append("''");
|
||||
} else {
|
||||
if (quoted) {
|
||||
target.append('\'');
|
||||
quoted = false;
|
||||
}
|
||||
target.append(ch);
|
||||
}
|
||||
}
|
||||
if (quoted) {
|
||||
target.append('\'');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
73
jdk/test/java/text/Format/MessageFormat/Bug7003643.java
Normal file
73
jdk/test/java/text/Format/MessageFormat/Bug7003643.java
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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 7003643
|
||||
* @summary Make sure MessageFormat.toPattern produces correct quoting. (SPI part is tested in PluggableLocale tests.)
|
||||
*/
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
public class Bug7003643 {
|
||||
private static final int N = 5;
|
||||
|
||||
private static final String[] elements = {
|
||||
"'{'", "'{", "{", "''", "}", "a", "'",
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
Random rand = new Random();
|
||||
int count = 0;
|
||||
int max = (int) (Math.pow((double)elements.length, (double)N)/0.52);
|
||||
while (count < max) {
|
||||
// Create a random pattern. If the produced pattern is
|
||||
// valid, then proceed with the round-trip testing.
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < N; i++) {
|
||||
sb.append(elements[rand.nextInt(elements.length)]);
|
||||
}
|
||||
String pattern = sb.toString();
|
||||
MessageFormat mf = null;
|
||||
try {
|
||||
mf = new MessageFormat(pattern);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// bad pattern data
|
||||
}
|
||||
if (mf == null) {
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
String res1 = MessageFormat.format(pattern, 123);
|
||||
String toPattern = mf.toPattern();
|
||||
String res2 = MessageFormat.format(toPattern, 123);
|
||||
if (!res1.equals(res2)) {
|
||||
String s = String.format("Failed%n pattern=\"%s\" => result=\"%s\"%n"
|
||||
+ " toPattern()=\"%s\" => result=\"%s\"%n",
|
||||
pattern, res1, toPattern, res2);
|
||||
throw new RuntimeException(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2010, 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
|
||||
@ -44,6 +44,7 @@ public class DateFormatProviderTest extends ProviderTest {
|
||||
availableLocalesTest();
|
||||
objectValidityTest();
|
||||
extendedVariantTest();
|
||||
messageFormatTest();
|
||||
}
|
||||
|
||||
void availableLocalesTest() {
|
||||
@ -118,4 +119,48 @@ public class DateFormatProviderTest extends ProviderTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final String[] TYPES = {
|
||||
"date",
|
||||
"time"
|
||||
};
|
||||
private static final String[] MODIFIERS = {
|
||||
"",
|
||||
"short",
|
||||
"medium", // Same as DEFAULT
|
||||
"long",
|
||||
"full"
|
||||
};
|
||||
|
||||
void messageFormatTest() {
|
||||
for (Locale target : providerloc) {
|
||||
for (String type : TYPES) {
|
||||
for (String modifier : MODIFIERS) {
|
||||
String pattern, expected;
|
||||
if (modifier.equals("")) {
|
||||
pattern = String.format("%s={0,%s}", type, type);
|
||||
} else {
|
||||
pattern = String.format("%s={0,%s,%s}", type, type, modifier);
|
||||
}
|
||||
if (modifier.equals("medium")) {
|
||||
// medium is default.
|
||||
expected = String.format("%s={0,%s}", type, type);
|
||||
} else {
|
||||
expected = pattern;
|
||||
}
|
||||
MessageFormat mf = new MessageFormat(pattern, target);
|
||||
Format[] fmts = mf.getFormats();
|
||||
if (fmts[0] instanceof SimpleDateFormat) {
|
||||
continue;
|
||||
}
|
||||
String toPattern = mf.toPattern();
|
||||
if (!toPattern.equals(expected)) {
|
||||
throw new RuntimeException("messageFormatTest: got '" + toPattern
|
||||
+ "', expected '" + expected + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2007, 2010, 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
|
||||
@ -23,6 +23,6 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# @test
|
||||
# @bug 4052440
|
||||
# @bug 4052440 7003643
|
||||
# @summary DateFormatProvider tests
|
||||
# @run shell ExecTest.sh foo DateFormatProviderTest true
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2010, 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
|
||||
@ -29,6 +29,8 @@ import java.util.*;
|
||||
import sun.util.*;
|
||||
import sun.util.resources.*;
|
||||
|
||||
import com.foo.FooNumberFormat;
|
||||
|
||||
public class NumberFormatProviderTest extends ProviderTest {
|
||||
|
||||
com.foo.NumberFormatProviderImpl nfp = new com.foo.NumberFormatProviderImpl();
|
||||
@ -43,6 +45,7 @@ public class NumberFormatProviderTest extends ProviderTest {
|
||||
NumberFormatProviderTest() {
|
||||
availableLocalesTest();
|
||||
objectValidityTest();
|
||||
messageFormatTest();
|
||||
}
|
||||
|
||||
void availableLocalesTest() {
|
||||
@ -72,14 +75,10 @@ public class NumberFormatProviderTest extends ProviderTest {
|
||||
}
|
||||
|
||||
// result object
|
||||
String resultCur =
|
||||
((DecimalFormat)NumberFormat.getCurrencyInstance(target)).toPattern();
|
||||
String resultInt =
|
||||
((DecimalFormat)NumberFormat.getIntegerInstance(target)).toPattern();
|
||||
String resultNum =
|
||||
((DecimalFormat)NumberFormat.getNumberInstance(target)).toPattern();
|
||||
String resultPer =
|
||||
((DecimalFormat)NumberFormat.getPercentInstance(target)).toPattern();
|
||||
String resultCur = getPattern(NumberFormat.getCurrencyInstance(target));
|
||||
String resultInt = getPattern(NumberFormat.getIntegerInstance(target));
|
||||
String resultNum = getPattern(NumberFormat.getNumberInstance(target));
|
||||
String resultPer = getPattern(NumberFormat.getPercentInstance(target));
|
||||
|
||||
// provider's object (if any)
|
||||
String providersCur = null;
|
||||
@ -87,21 +86,21 @@ public class NumberFormatProviderTest extends ProviderTest {
|
||||
String providersNum = null;
|
||||
String providersPer = null;
|
||||
if (providerloc.contains(target)) {
|
||||
DecimalFormat dfCur = (DecimalFormat)nfp.getCurrencyInstance(target);
|
||||
NumberFormat dfCur = nfp.getCurrencyInstance(target);
|
||||
if (dfCur != null) {
|
||||
providersCur = dfCur.toPattern();
|
||||
providersCur = getPattern(dfCur);
|
||||
}
|
||||
DecimalFormat dfInt = (DecimalFormat)nfp.getIntegerInstance(target);
|
||||
NumberFormat dfInt = nfp.getIntegerInstance(target);
|
||||
if (dfInt != null) {
|
||||
providersInt = dfInt.toPattern();
|
||||
providersInt = getPattern(dfInt);
|
||||
}
|
||||
DecimalFormat dfNum = (DecimalFormat)nfp.getNumberInstance(target);
|
||||
NumberFormat dfNum = nfp.getNumberInstance(target);
|
||||
if (dfNum != null) {
|
||||
providersNum = dfNum.toPattern();
|
||||
providersNum = getPattern(dfNum);
|
||||
}
|
||||
DecimalFormat dfPer = (DecimalFormat)nfp.getPercentInstance(target);
|
||||
NumberFormat dfPer = nfp.getPercentInstance(target);
|
||||
if (dfPer != null) {
|
||||
providersPer = dfPer.toPattern();
|
||||
providersPer = getPattern(dfPer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,4 +173,35 @@ public class NumberFormatProviderTest extends ProviderTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getPattern(NumberFormat nf) {
|
||||
if (nf instanceof DecimalFormat) {
|
||||
return ((DecimalFormat)nf).toPattern();
|
||||
}
|
||||
if (nf instanceof FooNumberFormat) {
|
||||
return ((FooNumberFormat)nf).toPattern();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final String[] NUMBER_PATTERNS = {
|
||||
"num={0,number}",
|
||||
"num={0,number,currency}",
|
||||
"num={0,number,percent}",
|
||||
"num={0,number,integer}"
|
||||
};
|
||||
|
||||
void messageFormatTest() {
|
||||
for (Locale target : providerloc) {
|
||||
for (String pattern : NUMBER_PATTERNS) {
|
||||
MessageFormat mf = new MessageFormat(pattern, target);
|
||||
String toPattern = mf.toPattern();
|
||||
if (!pattern.equals(toPattern)) {
|
||||
throw new RuntimeException("MessageFormat.toPattern: got '"
|
||||
+ toPattern
|
||||
+ "', expected '" + pattern + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2007, 2010, 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
|
||||
@ -23,6 +23,6 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# @test
|
||||
# @bug 4052440
|
||||
# @bug 4052440 7003643
|
||||
# @summary NumberFormatProvider tests
|
||||
# @run shell ExecTest.sh foo NumberFormatProviderTest true
|
||||
|
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2010, 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
|
||||
@ -42,7 +42,7 @@ public class DateFormatProviderImpl extends DateFormatProvider {
|
||||
|
||||
static String[] datePattern = {
|
||||
"yyyy'\u5e74'M'\u6708'd'\u65e5'", // full date pattern
|
||||
"yyyy/MM/dd", // long date pattern
|
||||
"yyyy/MMM/dd", // long date pattern
|
||||
"yyyy/MM/dd", // medium date pattern
|
||||
"yy/MM/dd" // short date pattern
|
||||
};
|
||||
@ -68,7 +68,7 @@ public class DateFormatProviderImpl extends DateFormatProvider {
|
||||
public DateFormat getDateInstance(int style, Locale locale) {
|
||||
for (int i = 0; i < avail.length; i ++) {
|
||||
if (Utils.supportsLocale(avail[i], locale)) {
|
||||
return new SimpleDateFormat(datePattern[style]+dialect[i], locale);
|
||||
return new FooDateFormat(datePattern[style]+dialect[i], locale);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("locale is not supported: "+locale);
|
||||
@ -77,7 +77,7 @@ public class DateFormatProviderImpl extends DateFormatProvider {
|
||||
public DateFormat getTimeInstance(int style, Locale locale) {
|
||||
for (int i = 0; i < avail.length; i ++) {
|
||||
if (Utils.supportsLocale(avail[i], locale)) {
|
||||
return new SimpleDateFormat(timePattern[style]+dialect[i], locale);
|
||||
return new FooDateFormat(timePattern[style]+dialect[i], locale);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("locale is not supported: "+locale);
|
||||
@ -86,7 +86,7 @@ public class DateFormatProviderImpl extends DateFormatProvider {
|
||||
public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) {
|
||||
for (int i = 0; i < avail.length; i ++) {
|
||||
if (Utils.supportsLocale(avail[i], locale)) {
|
||||
return new SimpleDateFormat(
|
||||
return new FooDateFormat(
|
||||
datePattern[dateStyle]+" "+timePattern[timeStyle]+dialect[i], locale);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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.
|
||||
*/
|
||||
|
||||
package com.foo;
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* FooDateFormat provides SimpleDateFormat methods required for the SPI testing.
|
||||
*/
|
||||
public class FooDateFormat extends DateFormat {
|
||||
private SimpleDateFormat sdf;
|
||||
|
||||
public FooDateFormat(String pattern, Locale loc) {
|
||||
sdf = new SimpleDateFormat(pattern, loc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer format(Date date,
|
||||
StringBuffer toAppendTo,
|
||||
FieldPosition fieldPosition) {
|
||||
return sdf.format(date, toAppendTo, fieldPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date parse(String source, ParsePosition pos) {
|
||||
return sdf.parse(source, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof FooDateFormat
|
||||
&& sdf.equals(((FooDateFormat)other).sdf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return sdf.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 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.
|
||||
*/
|
||||
|
||||
package com.foo;
|
||||
|
||||
import java.text.*;
|
||||
|
||||
/**
|
||||
* FooNumberFormat provides DecimalFormat methods required for the SPI testing.
|
||||
*/
|
||||
public class FooNumberFormat extends NumberFormat {
|
||||
private DecimalFormat df;
|
||||
|
||||
public FooNumberFormat(String pattern, DecimalFormatSymbols dfs) {
|
||||
df = new DecimalFormat(pattern, dfs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer format(double number,
|
||||
StringBuffer toAppendTo,
|
||||
FieldPosition pos) {
|
||||
return df.format(number, toAppendTo, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuffer format(long number,
|
||||
StringBuffer toAppendTo,
|
||||
FieldPosition pos) {
|
||||
return df.format(number, toAppendTo, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number parse(String source, ParsePosition parsePosition) {
|
||||
return df.parse(source, parsePosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof FooNumberFormat
|
||||
&& df.equals(((FooNumberFormat)other).df);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return df.hashCode();
|
||||
}
|
||||
|
||||
// DecimalFormat specific methods required for testing
|
||||
|
||||
public String toPattern() {
|
||||
return df.toPattern();
|
||||
}
|
||||
|
||||
public DecimalFormatSymbols getDecimalFormatSymbols() {
|
||||
return df.getDecimalFormatSymbols();
|
||||
}
|
||||
|
||||
public void setDecimalSeparatorAlwaysShown(boolean newValue) {
|
||||
df.setDecimalSeparatorAlwaysShown(newValue);
|
||||
}
|
||||
}
|
@ -28,6 +28,8 @@ FOOFILES_JAVA = \
|
||||
DateFormatSymbolsProviderImpl.java \
|
||||
DecimalFormatSymbolsProviderImpl.java \
|
||||
NumberFormatProviderImpl.java \
|
||||
FooDateFormat.java \
|
||||
FooNumberFormat.java \
|
||||
Utils.java
|
||||
|
||||
BARFILES_JAVA = \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2010, 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
|
||||
@ -49,13 +49,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider {
|
||||
|
||||
static String[] patterns = {
|
||||
"#,##0.###{0};-#,##0.###{1}", // decimal pattern
|
||||
"#{0};(#){1}", // integer pattern
|
||||
"\u00A4#,##0{0};-\u00A4#,##0{1}", // currency pattern
|
||||
"#,##0%{0}" // percent pattern
|
||||
};
|
||||
// Constants used by factory methods to specify a style of format.
|
||||
static final int NUMBERSTYLE = 0;
|
||||
static final int CURRENCYSTYLE = 1;
|
||||
static final int PERCENTSTYLE = 2;
|
||||
static final int INTEGERSTYLE = 1;
|
||||
static final int CURRENCYSTYLE = 2;
|
||||
static final int PERCENTSTYLE = 3;
|
||||
|
||||
public Locale[] getAvailableLocales() {
|
||||
return avail;
|
||||
@ -68,10 +70,10 @@ public class NumberFormatProviderImpl extends NumberFormatProvider {
|
||||
MessageFormat.format(patterns[CURRENCYSTYLE],
|
||||
dialect[i],
|
||||
dialect[i]);
|
||||
DecimalFormat df = new DecimalFormat(pattern,
|
||||
FooNumberFormat nf = new FooNumberFormat(pattern,
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
adjustForCurrencyDefaultFractionDigits(df);
|
||||
return df;
|
||||
adjustForCurrencyDefaultFractionDigits(nf);
|
||||
return nf;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("locale is not supported: "+locale);
|
||||
@ -81,15 +83,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider {
|
||||
for (int i = 0; i < avail.length; i ++) {
|
||||
if (Utils.supportsLocale(avail[i], locale)) {
|
||||
String pattern =
|
||||
MessageFormat.format(patterns[NUMBERSTYLE],
|
||||
MessageFormat.format(patterns[INTEGERSTYLE],
|
||||
dialect[i],
|
||||
dialect[i]);
|
||||
DecimalFormat df = new DecimalFormat(pattern,
|
||||
FooNumberFormat nf = new FooNumberFormat(pattern,
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
df.setMaximumFractionDigits(0);
|
||||
df.setDecimalSeparatorAlwaysShown(false);
|
||||
df.setParseIntegerOnly(true);
|
||||
return df;
|
||||
nf.setMaximumFractionDigits(0);
|
||||
nf.setDecimalSeparatorAlwaysShown(false);
|
||||
nf.setParseIntegerOnly(true);
|
||||
return nf;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("locale is not supported: "+locale);
|
||||
@ -102,7 +104,7 @@ public class NumberFormatProviderImpl extends NumberFormatProvider {
|
||||
MessageFormat.format(patterns[NUMBERSTYLE],
|
||||
dialect[i],
|
||||
dialect[i]);
|
||||
return new DecimalFormat(pattern,
|
||||
return new FooNumberFormat(pattern,
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
}
|
||||
@ -115,7 +117,7 @@ public class NumberFormatProviderImpl extends NumberFormatProvider {
|
||||
String pattern =
|
||||
MessageFormat.format(patterns[PERCENTSTYLE],
|
||||
dialect[i]);
|
||||
return new DecimalFormat(pattern,
|
||||
return new FooNumberFormat(pattern,
|
||||
DecimalFormatSymbols.getInstance(locale));
|
||||
}
|
||||
}
|
||||
@ -126,8 +128,8 @@ public class NumberFormatProviderImpl extends NumberFormatProvider {
|
||||
* Adjusts the minimum and maximum fraction digits to values that
|
||||
* are reasonable for the currency's default fraction digits.
|
||||
*/
|
||||
void adjustForCurrencyDefaultFractionDigits(DecimalFormat df) {
|
||||
DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
|
||||
void adjustForCurrencyDefaultFractionDigits(FooNumberFormat nf) {
|
||||
DecimalFormatSymbols dfs = nf.getDecimalFormatSymbols();
|
||||
Currency currency = dfs.getCurrency();
|
||||
if (currency == null) {
|
||||
try {
|
||||
@ -138,15 +140,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider {
|
||||
if (currency != null) {
|
||||
int digits = currency.getDefaultFractionDigits();
|
||||
if (digits != -1) {
|
||||
int oldMinDigits = df.getMinimumFractionDigits();
|
||||
int oldMinDigits = nf.getMinimumFractionDigits();
|
||||
// Common patterns are "#.##", "#.00", "#".
|
||||
// Try to adjust all of them in a reasonable way.
|
||||
if (oldMinDigits == df.getMaximumFractionDigits()) {
|
||||
df.setMinimumFractionDigits(digits);
|
||||
df.setMaximumFractionDigits(digits);
|
||||
if (oldMinDigits == nf.getMaximumFractionDigits()) {
|
||||
nf.setMinimumFractionDigits(digits);
|
||||
nf.setMaximumFractionDigits(digits);
|
||||
} else {
|
||||
df.setMinimumFractionDigits(Math.min(digits, oldMinDigits));
|
||||
df.setMaximumFractionDigits(digits);
|
||||
nf.setMinimumFractionDigits(Math.min(digits, oldMinDigits));
|
||||
nf.setMaximumFractionDigits(digits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user