提交 660d1da9 编写于 作者: O okutsu

7003643: [Fmt-Me] MessageFormat.toPattern produces wrong quoted string and subformat modifiers

7008195: [Fmt-Me] Improve MessageFormat.applyPattern performance
Reviewed-by: naoto, peytoia
上级 46ce17b5
/*
* 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);
}
}
}
}
/*
* 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 + "'");
}
}
}
}
}
}
#
# 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
/*
* 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 + "'");
}
}
}
}
}
#
# 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
/*
* 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);
}
}
......
/*
* 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();
}
}
/*
* 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 = \
......
/*
* 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);
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册