332 * Message formats are not synchronized.
333 * It is recommended to create separate format instances for each thread.
334 * If multiple threads access a format concurrently, it must be synchronized
335 * externally.
336 *
337 * @see java.util.Locale
338 * @see Format
339 * @see NumberFormat
340 * @see DecimalFormat
341 * @see DecimalFormatSymbols
342 * @see ChoiceFormat
343 * @see DateFormat
344 * @see SimpleDateFormat
345 *
346 * @author Mark Davis
347 * @since 1.1
348 */
349
350 public class MessageFormat extends Format {
351
352 private static final long serialVersionUID = 6479157306784022952L;
353
354 /**
355 * Constructs a MessageFormat for the default
356 * {@link java.util.Locale.Category#FORMAT FORMAT} locale and the
357 * specified pattern.
358 * The constructor first sets the locale, then parses the pattern and
359 * creates a list of subformats for the format elements contained in it.
360 * Patterns and their interpretation are specified in the
361 * <a href="#patterns">class description</a>.
362 *
363 * @param pattern the pattern for this message format
364 * @exception IllegalArgumentException if the pattern is invalid
365 * @exception NullPointerException if {@code pattern} is
366 * {@code null}
367 */
368 public MessageFormat(String pattern) {
369 this.locale = Locale.getDefault(Locale.Category.FORMAT);
370 applyPattern(pattern);
371 }
1136 }
1137
1138 /**
1139 * Generates a hash code for the message format object.
1140 */
1141 public int hashCode() {
1142 return pattern.hashCode(); // enough for reasonable distribution
1143 }
1144
1145
1146 /**
1147 * Defines constants that are used as attribute keys in the
1148 * <code>AttributedCharacterIterator</code> returned
1149 * from <code>MessageFormat.formatToCharacterIterator</code>.
1150 *
1151 * @since 1.4
1152 */
1153 public static class Field extends Format.Field {
1154
1155 // Proclaim serial compatibility with 1.4 FCS
1156 private static final long serialVersionUID = 7899943957617360810L;
1157
1158 /**
1159 * Creates a Field with the specified name.
1160 *
1161 * @param name Name of the attribute
1162 */
1163 protected Field(String name) {
1164 super(name);
1165 }
1166
1167 /**
1168 * Resolves instances being deserialized to the predefined constants.
1169 *
1170 * @throws InvalidObjectException if the constant could not be
1171 * resolved.
1172 * @return resolved MessageFormat.Field constant
1173 */
1174 protected Object readResolve() throws InvalidObjectException {
1175 if (this.getClass() != MessageFormat.Field.class) {
1176 throw new InvalidObjectException("subclass didn't correctly implement readResolve");
1177 }
1178
1179 return ARGUMENT;
1180 }
1181
1182 //
1183 // The constants
1184 //
1185
1186 /**
1187 * Constant identifying a portion of a message that was generated
1188 * from an argument passed into <code>formatToCharacterIterator</code>.
1189 * The value associated with the key will be an <code>Integer</code>
1190 * indicating the index in the <code>arguments</code> array of the
1191 * argument from which the text was generated.
1192 */
1193 public static final Field ARGUMENT =
1584 } else if (ch == '\'') {
1585 target.append("''");
1586 } else {
1587 if (quoted) {
1588 target.append('\'');
1589 quoted = false;
1590 }
1591 target.append(ch);
1592 }
1593 }
1594 if (quoted) {
1595 target.append('\'');
1596 }
1597 }
1598
1599 /**
1600 * After reading an object from the input stream, do a simple verification
1601 * to maintain class invariants.
1602 * @throws InvalidObjectException if the objects read from the stream is invalid.
1603 */
1604 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1605 in.defaultReadObject();
1606 boolean isValid = maxOffset >= -1
1607 && formats.length > maxOffset
1608 && offsets.length > maxOffset
1609 && argumentNumbers.length > maxOffset;
1610 if (isValid) {
1611 int lastOffset = pattern.length() + 1;
1612 for (int i = maxOffset; i >= 0; --i) {
1613 if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
1614 isValid = false;
1615 break;
1616 } else {
1617 lastOffset = offsets[i];
1618 }
1619 }
1620 }
1621 if (!isValid) {
1622 throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
1623 }
|
332 * Message formats are not synchronized.
333 * It is recommended to create separate format instances for each thread.
334 * If multiple threads access a format concurrently, it must be synchronized
335 * externally.
336 *
337 * @see java.util.Locale
338 * @see Format
339 * @see NumberFormat
340 * @see DecimalFormat
341 * @see DecimalFormatSymbols
342 * @see ChoiceFormat
343 * @see DateFormat
344 * @see SimpleDateFormat
345 *
346 * @author Mark Davis
347 * @since 1.1
348 */
349
350 public class MessageFormat extends Format {
351
352 @java.io.Serial
353 private static final long serialVersionUID = 6479157306784022952L;
354
355 /**
356 * Constructs a MessageFormat for the default
357 * {@link java.util.Locale.Category#FORMAT FORMAT} locale and the
358 * specified pattern.
359 * The constructor first sets the locale, then parses the pattern and
360 * creates a list of subformats for the format elements contained in it.
361 * Patterns and their interpretation are specified in the
362 * <a href="#patterns">class description</a>.
363 *
364 * @param pattern the pattern for this message format
365 * @exception IllegalArgumentException if the pattern is invalid
366 * @exception NullPointerException if {@code pattern} is
367 * {@code null}
368 */
369 public MessageFormat(String pattern) {
370 this.locale = Locale.getDefault(Locale.Category.FORMAT);
371 applyPattern(pattern);
372 }
1137 }
1138
1139 /**
1140 * Generates a hash code for the message format object.
1141 */
1142 public int hashCode() {
1143 return pattern.hashCode(); // enough for reasonable distribution
1144 }
1145
1146
1147 /**
1148 * Defines constants that are used as attribute keys in the
1149 * <code>AttributedCharacterIterator</code> returned
1150 * from <code>MessageFormat.formatToCharacterIterator</code>.
1151 *
1152 * @since 1.4
1153 */
1154 public static class Field extends Format.Field {
1155
1156 // Proclaim serial compatibility with 1.4 FCS
1157 @java.io.Serial
1158 private static final long serialVersionUID = 7899943957617360810L;
1159
1160 /**
1161 * Creates a Field with the specified name.
1162 *
1163 * @param name Name of the attribute
1164 */
1165 protected Field(String name) {
1166 super(name);
1167 }
1168
1169 /**
1170 * Resolves instances being deserialized to the predefined constants.
1171 *
1172 * @throws InvalidObjectException if the constant could not be
1173 * resolved.
1174 * @return resolved MessageFormat.Field constant
1175 */
1176 @java.io.Serial
1177 protected Object readResolve() throws InvalidObjectException {
1178 if (this.getClass() != MessageFormat.Field.class) {
1179 throw new InvalidObjectException("subclass didn't correctly implement readResolve");
1180 }
1181
1182 return ARGUMENT;
1183 }
1184
1185 //
1186 // The constants
1187 //
1188
1189 /**
1190 * Constant identifying a portion of a message that was generated
1191 * from an argument passed into <code>formatToCharacterIterator</code>.
1192 * The value associated with the key will be an <code>Integer</code>
1193 * indicating the index in the <code>arguments</code> array of the
1194 * argument from which the text was generated.
1195 */
1196 public static final Field ARGUMENT =
1587 } else if (ch == '\'') {
1588 target.append("''");
1589 } else {
1590 if (quoted) {
1591 target.append('\'');
1592 quoted = false;
1593 }
1594 target.append(ch);
1595 }
1596 }
1597 if (quoted) {
1598 target.append('\'');
1599 }
1600 }
1601
1602 /**
1603 * After reading an object from the input stream, do a simple verification
1604 * to maintain class invariants.
1605 * @throws InvalidObjectException if the objects read from the stream is invalid.
1606 */
1607 @java.io.Serial
1608 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1609 in.defaultReadObject();
1610 boolean isValid = maxOffset >= -1
1611 && formats.length > maxOffset
1612 && offsets.length > maxOffset
1613 && argumentNumbers.length > maxOffset;
1614 if (isValid) {
1615 int lastOffset = pattern.length() + 1;
1616 for (int i = maxOffset; i >= 0; --i) {
1617 if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
1618 isValid = false;
1619 break;
1620 } else {
1621 lastOffset = offsets[i];
1622 }
1623 }
1624 }
1625 if (!isValid) {
1626 throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
1627 }
|