예제 #1
0
  /**
   * Returns a copy of a {@link Message} that contains only fields that pass a filter. This will be
   * executed recursively for fields which are child messages.
   *
   * @param msg Message object
   * @param clearEmpty {@code true} will cause {@code null} to be returned if all fields from {@code
   *     msg} are removed; {@code false} will return an "empty" message in that case
   * @param filter Function that returns {@code true} to retain a field, {@code false} to discard
   * @return Message with the retained fieldsfrom {@code msg}. If some fields are retained and
   *     others discarded, returns a new message object. If all fields are retained, returns the
   *     same {@code msg} object. If all fields are discarded, returns {@code null} if {@code
   *     clearEmpty==true} or a default instance of {@code msg}'s message type if {@code
   *     clearEmpty==false}
   */
  @Nullable
  public static <M extends Message> M filter(
      M msg, boolean clearEmpty, Predicate<FieldDescriptor> filter) {
    checkNotNull(filter);

    int i = 0;
    for (Map.Entry<FieldDescriptor, Object> entry : msg.getAllFields().entrySet()) {
      FieldDescriptor fd = entry.getKey();

      if (!filter.test(fd)) {
        // At least one discarded field, go to slow-path.
        return filterFrom(msg, clearEmpty, filter, i);
      }

      ++i;
    }

    // Optimized common case: all items filtered, return the input sequence.
    return msg;
  }
예제 #2
0
  @Nullable
  private static <M extends Message> M filterFrom(
      M msg, boolean clearEmpty, Predicate<FieldDescriptor> filter, int firstDiscarded) {

    // At least one field was discarded; we have to work harder and maybe create
    // a new message that will contain only the retained filters. Use a lazy-allocated
    // builder to also optimize the scenario of all fields being discarded.

    Message.Builder builder = (firstDiscarded == 0) ? null : msg.newBuilderForType();
    Iterator<Map.Entry<FieldDescriptor, Object>> iter = msg.getAllFields().entrySet().iterator();

    for (int i = 0; i < firstDiscarded; ++i) {
      filterValue(clearEmpty, filter, builder, iter.next());
    }

    iter.next(); // Ignore object at firstDiscarded position

    while (iter.hasNext()) {
      Map.Entry<FieldDescriptor, Object> entry = iter.next();

      if (filter.test(entry.getKey())) {
        builder = (builder == null) ? msg.newBuilderForType() : builder;
        filterValue(clearEmpty, filter, builder, entry);
      }
    }

    if (builder == null) {
      if (clearEmpty) {
        return null;
      } else {
        @SuppressWarnings("unchecked")
        M ret = (M) msg.getDefaultInstanceForType();
        return ret;
      }
    } else {
      @SuppressWarnings("unchecked")
      M ret = (M) builder.build();
      return ret;
    }
  }