public List<MType> build() {
    // Now that build has been called, we are required to dispatch
    // invalidations.
    isClean = true;

    if (!isMessagesListMutable && builders == null) {
      // We still have an immutable list and we never created a builder.
      return messages;
    }

    boolean allMessagesInSync = true;
    if (!isMessagesListMutable) {
      // We still have an immutable list. Let's see if any of them are out
      // of sync with their builders.
      for (int i = 0; i < messages.size(); i++) {
        Message message = messages.get(i);
        SingleFieldBuilder<MType, BType, IType> builder = builders.get(i);
        if (builder != null) {
          if (builder.build() != message) {
            allMessagesInSync = false;
            break;
          }
        }
      }
      if (allMessagesInSync) {
        // Immutable list is still in sync.
        return messages;
      }
    }

    // Need to make sure messages is up to date
    ensureMutableMessageList();
    for (int i = 0; i < messages.size(); i++) {
      messages.set(i, getMessage(i, true));
    }

    // We're going to return our list as immutable so we mark that we can
    // no longer update it.
    messages = Collections.unmodifiableList(messages);
    isMessagesListMutable = false;
    return messages;
  }