/** Recursive helper implementing {@link #findMissingFields(Message)}. */ private static void findMissingFields( final Message message, final String prefix, final List<String> results) { for (final FieldDescriptor field : message.getDescriptorForType().getFields()) { if (field.isRequired() && !message.hasField(field)) { results.add(prefix + field.getName()); } } for (final Map.Entry<FieldDescriptor, Object> entry : message.getAllFields().entrySet()) { final FieldDescriptor field = entry.getKey(); final Object value = entry.getValue(); if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (field.isRepeated()) { int i = 0; for (final Object element : (List) value) { findMissingFields((Message) element, subMessagePrefix(prefix, field, i++), results); } } else { if (message.hasField(field)) { findMissingFields((Message) value, subMessagePrefix(prefix, field, -1), results); } } } } }
@Override public boolean equals(final Object other) { if (other == this) { return true; } if (!(other instanceof Message)) { return false; } final Message otherMessage = (Message) other; if (getDescriptorForType() != otherMessage.getDescriptorForType()) { return false; } return getAllFields().equals(otherMessage.getAllFields()) && getUnknownFields().equals(otherMessage.getUnknownFields()); }
@Override public BuilderType mergeFrom(final Message other) { if (other.getDescriptorForType() != getDescriptorForType()) { throw new IllegalArgumentException( "mergeFrom(Message) can only merge messages of the same type."); } // Note: We don't attempt to verify that other's fields have valid // types. Doing so would be a losing battle. We'd have to verify // all sub-messages as well, and we'd have to make copies of all of // them to insure that they don't change after verification (since // the Message interface itself cannot enforce immutability of // implementations). // TODO(kenton): Provide a function somewhere called makeDeepCopy() // which allows people to make secure deep copies of messages. for (final Map.Entry<FieldDescriptor, Object> entry : other.getAllFields().entrySet()) { final FieldDescriptor field = entry.getKey(); if (field.isRepeated()) { for (final Object element : (List) entry.getValue()) { addRepeatedField(field, element); } } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { final Message existingValue = (Message) getField(field); if (existingValue == existingValue.getDefaultInstanceForType()) { setField(field, entry.getValue()); } else { setField( field, existingValue .newBuilderForType() .mergeFrom(existingValue) .mergeFrom((Message) entry.getValue()) .build()); } } else { setField(field, entry.getValue()); } } mergeUnknownFields(other.getUnknownFields()); return (BuilderType) this; }
/** * Construct a {@link Message.Builder} for a message of the same type as {@code prototype}, and * initialize it with {@code prototype}'s contents. */ public static Builder newBuilder(Message prototype) { return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype); }
@Override public Descriptors.Descriptor getDescriptorForType() { return wrappedMessage.getDescriptorForType(); }