/**
* BreakIterator to use for capitalization
*/
- private BreakIterator capitalizationBrkIter = null;
+ private transient BreakIterator capitalizationBrkIter = null;
public static LocaleDisplayNames getInstance(ULocale locale, DialectHandling dialectHandling) {
private String adjustForUsageAndContext(CapitalizationContextUsage usage, String name) {
if (name != null && name.length() > 0 && UCharacter.isLowerCase(name.codePointAt(0)) &&
- capitalizationBrkIter != null &&
(capitalization==DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(capitalizationUsage != null && capitalizationUsage[usage.ordinal()]) )) {
// Note, won't have capitalizationUsage != null && capitalizationUsage[usage.ordinal()]
// unless capitalization is CAPITALIZATION_FOR_UI_LIST_OR_MENU or CAPITALIZATION_FOR_STANDALONE
+ if (capitalizationBrkIter == null) {
+ // should only happen when deserializing, etc.
+ capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
+ }
return UCharacter.toTitleCase(locale, name, capitalizationBrkIter,
UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
}
(fTimePattern == null || fCombinedFormat == null || combinedFormatHasDateAtStart) ) {
// capitalize relativeDayString according to context for relative, set formatter no context
if ( relativeDayString.length() > 0 && UCharacter.isLowerCase(relativeDayString.codePointAt(0)) &&
- capitalizationBrkIter != null &&
(capitalizationContext == DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(capitalizationContext == DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationOfRelativeUnitsForListOrMenu) ||
(capitalizationContext == DisplayContext.CAPITALIZATION_FOR_STANDALONE && capitalizationOfRelativeUnitsForStandAlone) )) {
+ if (capitalizationBrkIter == null) {
+ // should only happen when deserializing, etc.
+ capitalizationBrkIter = BreakIterator.getSentenceInstance(fLocale);
+ }
relativeDayString = UCharacter.toTitleCase(fLocale, relativeDayString, capitalizationBrkIter,
UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
}
private boolean capitalizationInfoIsSet = false;
private boolean capitalizationOfRelativeUnitsForListOrMenu = false;
private boolean capitalizationOfRelativeUnitsForStandAlone = false;
- private BreakIterator capitalizationBrkIter = null;
+ private transient BreakIterator capitalizationBrkIter = null;
/**
package com.ibm.icu.text;
+import java.io.IOException;
import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParseException;
private EnumSet<BooleanAttribute> booleanAttributes = EnumSet.allOf(BooleanAttribute.class);
/*
- * Capitalization setting, hoisted to DateFormat ICU 53
- * Currently no serialization in DateFormat, but SimpleDateFormat serialization
- * may call getContext/setContext to read/write this for compatibility
+ * Capitalization setting, hoisted to DateFormat ICU 53
+ * Note that SimpleDateFormat serialization may call getContext/setContext to read/write
+ * this for compatibility with serialization for its old copy of capitalizationSetting.
+ * @serial
+ */
+ private DisplayContext capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
+
+ static final int currentSerialVersion = 1;
+
+ /**
+ * Describes the version of <code>DateFormat</code> present on the stream.
+ * Possible values are:
+ * <ul>
+ * <li><b>0</b> (or uninitialized): the pre-ICU-53 version
+ *
+ * <li><b>1</b>: ICU 53, adds serialVersionOnStream and capitalizationSetting
+ * </ul>
+ * When streaming out a <code>DateFormat</code>, the most recent format
+ * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
+ * is always written.
+ *
+ * @serial
*/
- private transient DisplayContext capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
+ private int serialVersionOnStream = currentSerialVersion;
// Proclaim serial compatibility with 1.1 FCS
private static final long serialVersionUID = 7218322306649953788L;
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
DateFormat other = (DateFormat) obj;
- return (calendar.isEquivalentTo(other.calendar) &&
- numberFormat.equals(other.numberFormat));
+ return (((calendar==null && other.calendar==null) ||
+ (calendar!=null && other.calendar!=null && calendar.isEquivalentTo(other.calendar))) &&
+ ((numberFormat==null && other.numberFormat==null) ||
+ (numberFormat!=null && other.numberFormat!=null && numberFormat.equals(other.numberFormat))) &&
+ capitalizationSetting == other.capitalizationSetting);
}
/**
{
DateFormat other = (DateFormat) super.clone();
other.calendar = (Calendar) calendar.clone();
- other.numberFormat = (NumberFormat) numberFormat.clone();
+ if (numberFormat != null) {
+ other.numberFormat = (NumberFormat) numberFormat.clone();
+ }
return other;
}
}
}
+ /**
+ * First, read in the default serializable data.
+ *
+ * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
+ * the stream was written by a pre-ICU-53 version,
+ * set capitalizationSetting to a default value.
+ * Finally, set serialVersionOnStream back to the maximum allowed value so that
+ * default serialization will work properly if this object is streamed out again.
+ */
+ private void readObject(ObjectInputStream stream)
+ throws IOException, ClassNotFoundException
+ {
+ stream.defaultReadObject();
+ if (serialVersionOnStream < 1) {
+ // Didn't have capitalizationSetting, set it to default
+ capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
+ }
+ serialVersionOnStream = currentSerialVersion;
+ }
+
/**
* Creates a new date format.
* @stable ICU 2.0
private boolean capitalizationInfoIsSet = false;
private boolean capitalizationForListOrMenu = false;
private boolean capitalizationForStandAlone = false;
- private BreakIterator capitalizationBrkIter = null;
+ private transient BreakIterator capitalizationBrkIter = null;
private static final boolean DEBUG = ICUDebug.enabled("rbnf");
* Adjust capitalization of formatted result for display context
*/
private String adjustForContext(String result) {
- if (result != null && result.length() > 0 && UCharacter.isLowerCase(result.codePointAt(0)) &&
- capitalizationBrkIter != null) {
+ if (result != null && result.length() > 0 && UCharacter.isLowerCase(result.codePointAt(0))) {
DisplayContext capitalization = getContext(DisplayContext.Type.CAPITALIZATION);
if ( capitalization==DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(capitalization == DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForListOrMenu) ||
(capitalization == DisplayContext.CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone) ) {
+ if (capitalizationBrkIter == null) {
+ // should only happen when deserializing, etc.
+ capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
+ }
return UCharacter.toTitleCase(locale, result, capitalizationBrkIter,
UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
}
/**
* BreakIterator to use for capitalization
*/
- private BreakIterator capitalizationBrkIter = null;
+ private transient BreakIterator capitalizationBrkIter = null;
/*
* Capitalization setting, introduced in ICU 50
break;
} // switch (patternCharIndex)
- if (fieldNum == 0 && capitalizationContext != null && UCharacter.isLowerCase(buf.codePointAt(bufstart)) &&
- capitalizationBrkIter != null) {
+ if (fieldNum == 0 && capitalizationContext != null && UCharacter.isLowerCase(buf.codePointAt(bufstart))) {
boolean titlecase = false;
switch (capitalizationContext) {
case CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
break;
}
if (titlecase) {
+ if (capitalizationBrkIter == null) {
+ // should only happen when deserializing, etc.
+ capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
+ }
String firstField = buf.substring(bufstart); // bufstart or beginOffset, should be the same
String firstFieldTitleCase = UCharacter.toTitleCase(locale, firstField, capitalizationBrkIter,
UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
package com.ibm.icu.dev.test.format;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
import java.text.FieldPosition;
// now try context & standard format call
sdfmt.setContext(item.capitalizationContext);
+ SimpleDateFormat sdfmtClone = (SimpleDateFormat)sdfmt.clone();
+ if (!sdfmtClone.equals(sdfmt)) {
+ errln("FAIL: for locale " + item.locale + ", capitalizationContext " + item.capitalizationContext +
+ ", sdfmt.clone() != sdfmt (for SimpleDateFormat)");
+ }
+
StringBuffer result2 = new StringBuffer();
FieldPosition fpos2 = new FieldPosition(0);
sdfmt.format(cal, result2, fpos2);
// now try context & standard format call
dfmt.setContext(relItem.capitalizationContext);
+
+ // write to stream, then read a copy from stream & compare
+ boolean serializeTestFail = false;
+ ByteArrayOutputStream baos = null;
+ DateFormat dfmtFromStream = null;
+ try {
+ baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(dfmt);
+ oos.close();
+ } catch (IOException i) {
+ errln("FAIL: for locale " + relItem.locale + ", capitalizationContext " + relItem.capitalizationContext +
+ ", serialization of RELATIVE_LONG DateFormat fails with IOException");
+ serializeTestFail = true;
+ }
+ if (!serializeTestFail) {
+ byte[] buf = baos.toByteArray();
+ try {
+ ByteArrayInputStream bais = new ByteArrayInputStream(buf);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ dfmtFromStream = (DateFormat)ois.readObject();
+ ois.close();
+ } catch (IOException i) {
+ errln("FAIL: for locale " + relItem.locale + ", capitalizationContext " + relItem.capitalizationContext +
+ ", deserialization of RELATIVE_LONG DateFormat fails with IOException");
+ serializeTestFail = true;
+ } catch (ClassNotFoundException c) {
+ errln("FAIL: for locale " + relItem.locale + ", capitalizationContext " + relItem.capitalizationContext +
+ ", deserialization of RELATIVE_LONG DateFormat fails with ClassNotFoundException");
+ serializeTestFail = true;
+ }
+ }
+ if (!serializeTestFail && dfmtFromStream==null) {
+ errln("FAIL: for locale " + relItem.locale + ", capitalizationContext " + relItem.capitalizationContext +
+ ", dfmtFromStream is null (for RELATIVE_LONG)");
+ serializeTestFail = true;
+ }
+ if (!serializeTestFail && !dfmtFromStream.equals(dfmt)) {
+ errln("FAIL: for locale " + relItem.locale + ", capitalizationContext " + relItem.capitalizationContext +
+ ", dfmtFromStream != dfmt (for RELATIVE_LONG)");
+ serializeTestFail = true;
+ }
+
cal.setTime(today);
StringBuffer result2 = new StringBuffer();
FieldPosition fpos2 = new FieldPosition(0);
errln("FAIL: format today for locale " + relItem.locale + ", capitalizationContext " + relItem.capitalizationContext +
", expected \"" + relItem.expectedFormatToday + "\", got \"" + result2 + "\"");
}
+ if (!serializeTestFail) {
+ result2.setLength(0);
+ dfmtFromStream.format(cal, result2, fpos2);
+ if (result2.toString().compareTo(relItem.expectedFormatToday) != 0) {
+ errln("FAIL: use dfmtFromStream to format today for locale " + relItem.locale + ", capitalizationContext " +
+ relItem.capitalizationContext + ", expected \"" + relItem.expectedFormatToday + "\", got \"" + result2 + "\"");
+ }
+ }
+
cal.add(Calendar.DATE, -1);
result2.setLength(0);
dfmt.format(cal, result2, fpos2);