ICU-10268 Be sure that MeasureFormat and sub classes correctly implement clone() and getLocale(ULocale.VALID_LOCALE)
X-SVN-Rev: 34780
This commit is contained in:
parent
a53682a55e
commit
3ef485dccf
@ -38,9 +38,22 @@ class CurrencyFormat extends MeasureFormat {
|
||||
private transient final MeasureFormat mf;
|
||||
|
||||
public CurrencyFormat(ULocale locale) {
|
||||
// Needed for getLocale(ULocale.VALID_LOCALE).
|
||||
setLocale(locale, locale);
|
||||
mf = MeasureFormat.getInstance(locale, FormatWidth.WIDE);
|
||||
fmt = NumberFormat.getCurrencyInstance(locale.toLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
CurrencyFormat result = (CurrencyFormat) super.clone();
|
||||
result.fmt = (NumberFormat) fmt.clone();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override Format.format().
|
||||
@ -73,33 +86,57 @@ class CurrencyFormat extends MeasureFormat {
|
||||
// boilerplate code to make CurrencyFormat otherwise follow the contract of
|
||||
// MeasureFormat
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public String formatMeasures(Measure... measures) {
|
||||
return mf.formatMeasures(measures);
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public <T extends Appendable> T formatMeasure(
|
||||
Measure measure, T appendable, FieldPosition fieldPosition) {
|
||||
return mf.formatMeasure(measure, appendable, fieldPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public <T extends Appendable> T formatMeasures(
|
||||
T appendable, FieldPosition fieldPosition, Measure... measures) {
|
||||
return mf.formatMeasures(appendable, fieldPosition, measures);
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public MeasureFormat.FormatWidth getWidth() {
|
||||
return mf.getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public ULocale getLocale() {
|
||||
return mf.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public NumberFormat getNumberFormat() {
|
||||
return mf.getNumberFormat();
|
||||
@ -107,15 +144,18 @@ class CurrencyFormat extends MeasureFormat {
|
||||
|
||||
// End boilerplate.
|
||||
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getLocale().hashCode() + 154321962;
|
||||
return mf.hashCode() + 154321962;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean equalsSameClass(MeasureFormat other) {
|
||||
return getLocale().equals(other.getLocale());
|
||||
boolean equalsSameClass(MeasureFormat other) {
|
||||
return mf.equals(((CurrencyFormat) other).mf);
|
||||
}
|
||||
|
||||
// Serialization
|
||||
|
@ -94,8 +94,6 @@ public class MeasureFormat extends UFormat {
|
||||
// Generated by serialver from JDK 1.4.1_01
|
||||
static final long serialVersionUID = -7182021401701778240L;
|
||||
|
||||
private final transient ULocale locale;
|
||||
|
||||
// NumberFormat is known to lack thread-safety, all access to this
|
||||
// field must be synchronized.
|
||||
private final transient NumberFormat numberFormat;
|
||||
@ -339,7 +337,7 @@ public class MeasureFormat extends UFormat {
|
||||
results[i] = formatMeasure(measures[i], new StringBuilder(), dummyPos);
|
||||
}
|
||||
}
|
||||
ListFormatter listFormatter = ListFormatter.getInstance(locale,
|
||||
ListFormatter listFormatter = ListFormatter.getInstance(getLocale(),
|
||||
length == FormatWidth.WIDE ? ListFormatter.Style.DURATION : ListFormatter.Style.DURATION_SHORT);
|
||||
|
||||
// Fix up FieldPosition indexes if our field is found.
|
||||
@ -393,19 +391,16 @@ public class MeasureFormat extends UFormat {
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (numberFormat.hashCode() * 31 + locale.hashCode()) * 31 + length.hashCode();
|
||||
return (numberFormat.hashCode() * 31 + getLocale().hashCode()) * 31 + length.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this object is equal to other. The class of this and the class of other
|
||||
* are guaranteed to be equal.
|
||||
*
|
||||
* @deprecated For ICU internal use only.
|
||||
* @internal
|
||||
*/
|
||||
protected boolean equalsSameClass(MeasureFormat other) {
|
||||
boolean equalsSameClass(MeasureFormat other) {
|
||||
return objEquals(numberFormat,other.numberFormat)
|
||||
&& objEquals(locale, other.locale) && objEquals(length, other.length);
|
||||
&& objEquals(getLocale(), other.getLocale()) && objEquals(length, other.length);
|
||||
}
|
||||
|
||||
|
||||
@ -424,7 +419,7 @@ public class MeasureFormat extends UFormat {
|
||||
* @provisional
|
||||
*/
|
||||
public ULocale getLocale() {
|
||||
return locale;
|
||||
return getLocale(ULocale.VALID_LOCALE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -466,7 +461,7 @@ public class MeasureFormat extends UFormat {
|
||||
|
||||
MeasureFormat withNumberFormat(NumberFormat format) {
|
||||
return new MeasureFormat(
|
||||
this.locale,
|
||||
getLocale(),
|
||||
this.length,
|
||||
(NumberFormat) format.clone(),
|
||||
this.rules,
|
||||
@ -479,7 +474,7 @@ public class MeasureFormat extends UFormat {
|
||||
NumberFormat format,
|
||||
PluralRules rules,
|
||||
Map<MeasureUnit, EnumMap<FormatWidth, Map<String, PatternData>>> unitToStyleToCountToFormat) {
|
||||
this.locale = locale;
|
||||
setLocale(locale, locale);
|
||||
this.length = width;
|
||||
this.numberFormat = format;
|
||||
this.rules = rules;
|
||||
@ -494,7 +489,6 @@ public class MeasureFormat extends UFormat {
|
||||
protected MeasureFormat() {
|
||||
// Make compiler happy by setting final fields to null.
|
||||
this.length = null;
|
||||
this.locale = null;
|
||||
this.numberFormat = null;
|
||||
this.rules = null;
|
||||
this.unitToStyleToCountToFormat = null;
|
||||
@ -607,16 +601,16 @@ public class MeasureFormat extends UFormat {
|
||||
}
|
||||
|
||||
Object toTimeUnitProxy() {
|
||||
return new MeasureProxy(locale, length, numberFormat, TIME_UNIT_FORMAT);
|
||||
return new MeasureProxy(getLocale(), length, numberFormat, TIME_UNIT_FORMAT);
|
||||
}
|
||||
|
||||
Object toCurrencyProxy() {
|
||||
return new MeasureProxy(locale, length, numberFormat, CURRENCY_FORMAT);
|
||||
return new MeasureProxy(getLocale(), length, numberFormat, CURRENCY_FORMAT);
|
||||
}
|
||||
|
||||
private Object writeReplace() throws ObjectStreamException {
|
||||
return new MeasureProxy(
|
||||
locale, length, numberFormat, MEASURE_FORMAT);
|
||||
getLocale(), length, numberFormat, MEASURE_FORMAT);
|
||||
}
|
||||
|
||||
static class MeasureProxy implements Externalizable {
|
||||
|
@ -147,13 +147,18 @@ public class TimeUnitFormat extends MeasureFormat {
|
||||
mf = MeasureFormat.getInstance(
|
||||
locale, style == FULL_NAME ? FormatWidth.WIDE : FormatWidth.SHORT);
|
||||
this.style = style;
|
||||
|
||||
// Needed for getLocale(ULocale.VALID_LOCALE)
|
||||
setLocale(locale, locale);
|
||||
this.locale = locale;
|
||||
isReady = false;
|
||||
}
|
||||
|
||||
private TimeUnitFormat(ULocale locale, int style, NumberFormat numberFormat) {
|
||||
this(locale, style);
|
||||
setNumberFormat(numberFormat);
|
||||
if (numberFormat != null) {
|
||||
setNumberFormat((NumberFormat) numberFormat.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,8 +176,11 @@ public class TimeUnitFormat extends MeasureFormat {
|
||||
* @stable ICU 4.0
|
||||
*/
|
||||
public TimeUnitFormat setLocale(ULocale locale) {
|
||||
if (locale != this.locale){
|
||||
if (locale != this.locale){
|
||||
mf = mf.withLocale(locale);
|
||||
|
||||
// Needed for getLocale(ULocale.VALID_LOCALE)
|
||||
setLocale(locale, locale);
|
||||
this.locale = locale;
|
||||
isReady = false;
|
||||
}
|
||||
@ -325,6 +333,8 @@ public class TimeUnitFormat extends MeasureFormat {
|
||||
} else {
|
||||
locale = ULocale.getDefault(Category.FORMAT);
|
||||
}
|
||||
// Needed for getLocale(ULocale.VALID_LOCALE)
|
||||
setLocale(locale, locale);
|
||||
}
|
||||
if (format == null) {
|
||||
format = NumberFormat.getNumberInstance(locale);
|
||||
@ -506,33 +516,68 @@ if ( searchPluralCount.equals("other") ) {
|
||||
// boilerplate code to make TimeUnitFormat otherwise follow the contract of
|
||||
// MeasureFormat
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public String formatMeasures(Measure... measures) {
|
||||
return mf.formatMeasures(measures);
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public <T extends Appendable> T formatMeasure(
|
||||
Measure measure, T appendable, FieldPosition fieldPosition) {
|
||||
return mf.formatMeasure(measure, appendable, fieldPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public <T extends Appendable> T formatMeasures(
|
||||
T appendable, FieldPosition fieldPosition, Measure... measures) {
|
||||
return mf.formatMeasures(appendable, fieldPosition, measures);
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public MeasureFormat.FormatWidth getWidth() {
|
||||
return mf.getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public ULocale getLocale() {
|
||||
return mf.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public Object clone() {
|
||||
TimeUnitFormat result = (TimeUnitFormat) super.clone();
|
||||
result.format = (NumberFormat) format.clone();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public NumberFormat getNumberFormat() {
|
||||
return mf.getNumberFormat();
|
||||
@ -542,14 +587,18 @@ if ( searchPluralCount.equals("other") ) {
|
||||
|
||||
// equals / hashcode
|
||||
|
||||
/**
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getLocale().hashCode() + 911247101;
|
||||
return mf.hashCode() + 911247101;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean equalsSameClass(MeasureFormat other) {
|
||||
return getLocale().equals(other.getLocale());
|
||||
boolean equalsSameClass(MeasureFormat other) {
|
||||
return mf.equals(((TimeUnitFormat) other).mf);
|
||||
}
|
||||
|
||||
// End equals / hashcode
|
||||
|
@ -28,6 +28,7 @@ import com.ibm.icu.text.DecimalFormat;
|
||||
import com.ibm.icu.text.MeasureFormat;
|
||||
import com.ibm.icu.text.MeasureFormat.FormatWidth;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.TimeUnitFormat;
|
||||
import com.ibm.icu.util.Currency;
|
||||
import com.ibm.icu.util.Measure;
|
||||
import com.ibm.icu.util.MeasureUnit;
|
||||
@ -299,6 +300,20 @@ public class MeasureUnitTest extends TestFmwk {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testEqHashCode() {
|
||||
MeasureFormat mf = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.SHORT);
|
||||
MeasureFormat mfeq = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.SHORT);
|
||||
MeasureFormat mfne = MeasureFormat.getInstance(ULocale.CANADA, FormatWidth.WIDE);
|
||||
MeasureFormat mfne2 = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.SHORT);
|
||||
verifyEqualsHashCode(mf, mfeq, mfne);
|
||||
verifyEqualsHashCode(mf, mfeq, mfne2);
|
||||
}
|
||||
|
||||
public void testGetLocale() {
|
||||
MeasureFormat mf = MeasureFormat.getInstance(ULocale.GERMAN, FormatWidth.SHORT);
|
||||
assertEquals("", ULocale.GERMAN, mf.getLocale(ULocale.VALID_LOCALE));
|
||||
}
|
||||
|
||||
static void generateConstants() {
|
||||
System.out.println("static final MeasureUnit");
|
||||
@ -384,6 +399,18 @@ public class MeasureUnitTest extends TestFmwk {
|
||||
return b.append(']').toString();
|
||||
}
|
||||
|
||||
private void verifyEqualsHashCode(Object o, Object eq, Object ne) {
|
||||
assertEquals("verifyEqualsHashCodeSame", o, o);
|
||||
assertEquals("verifyEqualsHashCodeEq", o, eq);
|
||||
assertNotEquals("verifyEqualsHashCodeNe", o, ne);
|
||||
assertNotEquals("verifyEqualsHashCodeEqTrans", eq, ne);
|
||||
assertEquals("verifyEqualsHashCodeHashEq", o.hashCode(), eq.hashCode());
|
||||
|
||||
// May be a flaky test, but generally should be true.
|
||||
// May need to comment this out later.
|
||||
assertNotEquals("verifyEqualsHashCodeHashNe", o.hashCode(), ne.hashCode());
|
||||
}
|
||||
|
||||
public static class MeasureUnitHandler implements SerializableTest.Handler
|
||||
{
|
||||
public Object[] getTestObjects()
|
||||
|
@ -12,8 +12,10 @@ import java.util.Locale;
|
||||
|
||||
import com.ibm.icu.dev.test.TestFmwk;
|
||||
import com.ibm.icu.math.BigDecimal;
|
||||
import com.ibm.icu.text.MeasureFormat;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.TimeUnitFormat;
|
||||
import com.ibm.icu.text.MeasureFormat.FormatWidth;
|
||||
import com.ibm.icu.util.TimeUnit;
|
||||
import com.ibm.icu.util.TimeUnitAmount;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
@ -113,6 +115,30 @@ public class TimeUnitTest extends TestFmwk {
|
||||
format.setNumberFormat(NumberFormat.getNumberInstance(new Locale("en")));
|
||||
formatParsing(format);
|
||||
}
|
||||
|
||||
public void TestClone() {
|
||||
TimeUnitFormat tuf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.ABBREVIATED_NAME);
|
||||
NumberFormat nf = NumberFormat.getInstance();
|
||||
tuf.setNumberFormat(nf);
|
||||
TimeUnitFormat tufClone = (TimeUnitFormat) tuf.clone();
|
||||
tuf.setLocale(Locale.GERMAN);
|
||||
assertEquals("", "1 hr", tufClone.format(new TimeUnitAmount(1, TimeUnit.HOUR)));
|
||||
}
|
||||
|
||||
public void TestEqHashCode() {
|
||||
TimeUnitFormat tf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.FULL_NAME);
|
||||
MeasureFormat tfeq = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.FULL_NAME);
|
||||
|
||||
MeasureFormat tfne = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.ABBREVIATED_NAME);
|
||||
MeasureFormat tfne2 = new TimeUnitFormat(ULocale.GERMAN, TimeUnitFormat.FULL_NAME);
|
||||
verifyEqualsHashCode(tf, tfeq, tfne);
|
||||
verifyEqualsHashCode(tf, tfeq, tfne2);
|
||||
}
|
||||
|
||||
public void TestGetLocale() {
|
||||
TimeUnitFormat tf = new TimeUnitFormat(ULocale.GERMAN);
|
||||
assertEquals("", ULocale.GERMAN, tf.getLocale(ULocale.VALID_LOCALE));
|
||||
}
|
||||
|
||||
/*
|
||||
* @bug 7902
|
||||
@ -353,4 +379,16 @@ public class TimeUnitTest extends TestFmwk {
|
||||
tuf1.setNumberFormat(NumberFormat.getInstance());
|
||||
tuf1.parseObject("", new ParsePosition(0));
|
||||
}
|
||||
|
||||
private void verifyEqualsHashCode(Object o, Object eq, Object ne) {
|
||||
assertEquals("verifyEqualsHashCodeSame", o, o);
|
||||
assertEquals("verifyEqualsHashCodeEq", o, eq);
|
||||
assertNotEquals("verifyEqualsHashCodeNe", o, ne);
|
||||
assertNotEquals("verifyEqualsHashCodeEqTrans", eq, ne);
|
||||
assertEquals("verifyEqualsHashCodeHashEq", o.hashCode(), eq.hashCode());
|
||||
|
||||
// May be a flaky test, but generally should be true.
|
||||
// May need to comment this out later.
|
||||
assertNotEquals("verifyEqualsHashCodeHashNe", o.hashCode(), ne.hashCode());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user