code: private void writeObject(java.io.ObjectOutputStream out) throws IOException {
          out.defaultWriteObject();
          // ICU 4.8 custom serialization.
          // locale as a BCP 47 language tag
          out.writeObject(ulocale.toLanguageTag());
          // ApostropheMode
          if (msgPattern == null) {
              msgPattern = new MessagePattern();
          }
          out.writeObject(msgPattern.getApostropheMode());
          // message pattern string
          out.writeObject(msgPattern.getPatternString());
          // custom formatters
          if (customFormatArgStarts == null || customFormatArgStarts.isEmpty()) {
              out.writeInt(0);
          } else {
              out.writeInt(customFormatArgStarts.size());
              int formatIndex = 0;
              for (int partIndex = 0; (partIndex = nextTopLevelArgStart(partIndex)) >= 0;) {
                  if (customFormatArgStarts.contains(partIndex)) {
                      out.writeInt(formatIndex);
                      out.writeObject(cachedFormatters.get(partIndex));
                  }
                  ++formatIndex;
              }
          }
          // number of future (int, Object) pairs
          out.writeInt(0);
      }
docs: Custom serialization, new in ICU 4.8.
  We do not want to use default serialization because we only have a small
  amount of persistent state which is better expressed explicitly
  rather than via writing field objects.
  @param out The output stream.
  @serialData Writes the locale as a BCP 47 language tag string,
  the MessagePattern.ApostropheMode as an object,
  and the pattern string (null if none was applied).
  Followed by an int with the number of (int formatIndex, Object formatter) pairs,
  and that many such pairs, corresponding to previous setFormat() calls for custom formats.
  Followed by an int with the number of (int, Object) pairs,
  and that many such pairs, for future (post-ICU 4.8) extension of the serialization format.