Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 package com.google.protobuf;
     32 
     33 import com.google.protobuf.Descriptors.Descriptor;
     34 import com.google.protobuf.Descriptors.FieldDescriptor;
     35 import com.google.protobuf.GeneratedMessage.ExtendableBuilder;
     36 import com.google.protobuf.Internal.EnumLite;
     37 
     38 import java.io.IOException;
     39 import java.io.InputStream;
     40 import java.util.ArrayList;
     41 import java.util.List;
     42 import java.util.Map;
     43 
     44 /**
     45  * A partial implementation of the {@link Message} interface which implements
     46  * as many methods of that interface as possible in terms of other methods.
     47  *
     48  * @author kenton (at) google.com Kenton Varda
     49  */
     50 public abstract class AbstractMessage extends AbstractMessageLite
     51                                       implements Message {
     52   @SuppressWarnings("unchecked")
     53   public boolean isInitialized() {
     54     // Check that all required fields are present.
     55     for (final FieldDescriptor field : getDescriptorForType().getFields()) {
     56       if (field.isRequired()) {
     57         if (!hasField(field)) {
     58           return false;
     59         }
     60       }
     61     }
     62 
     63     // Check that embedded messages are initialized.
     64     for (final Map.Entry<FieldDescriptor, Object> entry :
     65         getAllFields().entrySet()) {
     66       final FieldDescriptor field = entry.getKey();
     67       if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
     68         if (field.isRepeated()) {
     69           for (final Message element : (List<Message>) entry.getValue()) {
     70             if (!element.isInitialized()) {
     71               return false;
     72             }
     73           }
     74         } else {
     75           if (!((Message) entry.getValue()).isInitialized()) {
     76             return false;
     77           }
     78         }
     79       }
     80     }
     81 
     82     return true;
     83   }
     84 
     85   public List<String> findInitializationErrors() {
     86     return Builder.findMissingFields(this);
     87   }
     88 
     89   public String getInitializationErrorString() {
     90     return delimitWithCommas(findInitializationErrors());
     91   }
     92 
     93   private static String delimitWithCommas(List<String> parts) {
     94     StringBuilder result = new StringBuilder();
     95     for (String part : parts) {
     96       if (result.length() > 0) {
     97         result.append(", ");
     98       }
     99       result.append(part);
    100     }
    101     return result.toString();
    102   }
    103 
    104   @Override
    105   public final String toString() {
    106     return TextFormat.printToString(this);
    107   }
    108 
    109   public void writeTo(final CodedOutputStream output) throws IOException {
    110     final boolean isMessageSet =
    111         getDescriptorForType().getOptions().getMessageSetWireFormat();
    112 
    113     for (final Map.Entry<FieldDescriptor, Object> entry :
    114         getAllFields().entrySet()) {
    115       final FieldDescriptor field = entry.getKey();
    116       final Object value = entry.getValue();
    117       if (isMessageSet && field.isExtension() &&
    118           field.getType() == FieldDescriptor.Type.MESSAGE &&
    119           !field.isRepeated()) {
    120         output.writeMessageSetExtension(field.getNumber(), (Message) value);
    121       } else {
    122         FieldSet.writeField(field, value, output);
    123       }
    124     }
    125 
    126     final UnknownFieldSet unknownFields = getUnknownFields();
    127     if (isMessageSet) {
    128       unknownFields.writeAsMessageSetTo(output);
    129     } else {
    130       unknownFields.writeTo(output);
    131     }
    132   }
    133 
    134   private int memoizedSize = -1;
    135 
    136   public int getSerializedSize() {
    137     int size = memoizedSize;
    138     if (size != -1) {
    139       return size;
    140     }
    141 
    142     size = 0;
    143     final boolean isMessageSet =
    144         getDescriptorForType().getOptions().getMessageSetWireFormat();
    145 
    146     for (final Map.Entry<FieldDescriptor, Object> entry :
    147         getAllFields().entrySet()) {
    148       final FieldDescriptor field = entry.getKey();
    149       final Object value = entry.getValue();
    150       if (isMessageSet && field.isExtension() &&
    151           field.getType() == FieldDescriptor.Type.MESSAGE &&
    152           !field.isRepeated()) {
    153         size += CodedOutputStream.computeMessageSetExtensionSize(
    154             field.getNumber(), (Message) value);
    155       } else {
    156         size += FieldSet.computeFieldSize(field, value);
    157       }
    158     }
    159 
    160     final UnknownFieldSet unknownFields = getUnknownFields();
    161     if (isMessageSet) {
    162       size += unknownFields.getSerializedSizeAsMessageSet();
    163     } else {
    164       size += unknownFields.getSerializedSize();
    165     }
    166 
    167     memoizedSize = size;
    168     return size;
    169   }
    170 
    171   @Override
    172   public boolean equals(final Object other) {
    173     if (other == this) {
    174       return true;
    175     }
    176     if (!(other instanceof Message)) {
    177       return false;
    178     }
    179     final Message otherMessage = (Message) other;
    180     if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
    181       return false;
    182     }
    183     return getAllFields().equals(otherMessage.getAllFields()) &&
    184         getUnknownFields().equals(otherMessage.getUnknownFields());
    185   }
    186 
    187   @Override
    188   public int hashCode() {
    189     int hash = 41;
    190     hash = (19 * hash) + getDescriptorForType().hashCode();
    191     hash = hashFields(hash, getAllFields());
    192     hash = (29 * hash) + getUnknownFields().hashCode();
    193     return hash;
    194   }
    195 
    196   /** Get a hash code for given fields and values, using the given seed. */
    197   @SuppressWarnings("unchecked")
    198   protected int hashFields(int hash, Map<FieldDescriptor, Object> map) {
    199     for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
    200       FieldDescriptor field = entry.getKey();
    201       Object value = entry.getValue();
    202       hash = (37 * hash) + field.getNumber();
    203       if (field.getType() != FieldDescriptor.Type.ENUM){
    204         hash = (53 * hash) + value.hashCode();
    205       } else if (field.isRepeated()) {
    206         List<? extends EnumLite> list = (List<? extends EnumLite>) value;
    207         hash = (53 * hash) + hashEnumList(list);
    208       } else {
    209         hash = (53 * hash) + hashEnum((EnumLite) value);
    210       }
    211     }
    212     return hash;
    213   }
    214 
    215   /**
    216    * Helper method for implementing {@link Message#hashCode()}.
    217    * @see Boolean#hashCode()
    218    */
    219   protected static int hashLong(long n) {
    220     return (int) (n ^ (n >>> 32));
    221   }
    222 
    223   /**
    224    * Helper method for implementing {@link Message#hashCode()}.
    225    * @see Boolean#hashCode()
    226    */
    227   protected static int hashBoolean(boolean b) {
    228     return b ? 1231 : 1237;
    229   }
    230 
    231   /**
    232    * Package private helper method for AbstractParser to create
    233    * UninitializedMessageException with missing field information.
    234    */
    235   @Override
    236   UninitializedMessageException newUninitializedMessageException() {
    237     return Builder.newUninitializedMessageException(this);
    238   }
    239 
    240   /**
    241    * Helper method for implementing {@link Message#hashCode()}.
    242    * <p>
    243    * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
    244    * need to use the field number as the hash code to ensure compatibility
    245    * between statically and dynamically generated enum objects.
    246    */
    247   protected static int hashEnum(EnumLite e) {
    248     return e.getNumber();
    249   }
    250 
    251   /** Helper method for implementing {@link Message#hashCode()}. */
    252   protected static int hashEnumList(List<? extends EnumLite> list) {
    253     int hash = 1;
    254     for (EnumLite e : list) {
    255       hash = 31 * hash + hashEnum(e);
    256     }
    257     return hash;
    258   }
    259 
    260   // =================================================================
    261 
    262   /**
    263    * A partial implementation of the {@link Message.Builder} interface which
    264    * implements as many methods of that interface as possible in terms of
    265    * other methods.
    266    */
    267   @SuppressWarnings("unchecked")
    268   public static abstract class Builder<BuilderType extends Builder>
    269       extends AbstractMessageLite.Builder<BuilderType>
    270       implements Message.Builder {
    271     // The compiler produces an error if this is not declared explicitly.
    272     @Override
    273     public abstract BuilderType clone();
    274 
    275     public BuilderType clear() {
    276       for (final Map.Entry<FieldDescriptor, Object> entry :
    277            getAllFields().entrySet()) {
    278         clearField(entry.getKey());
    279       }
    280       return (BuilderType) this;
    281     }
    282 
    283     public List<String> findInitializationErrors() {
    284       return findMissingFields(this);
    285     }
    286 
    287     public String getInitializationErrorString() {
    288       return delimitWithCommas(findInitializationErrors());
    289     }
    290 
    291     public BuilderType mergeFrom(final Message other) {
    292       if (other.getDescriptorForType() != getDescriptorForType()) {
    293         throw new IllegalArgumentException(
    294           "mergeFrom(Message) can only merge messages of the same type.");
    295       }
    296 
    297       // Note:  We don't attempt to verify that other's fields have valid
    298       //   types.  Doing so would be a losing battle.  We'd have to verify
    299       //   all sub-messages as well, and we'd have to make copies of all of
    300       //   them to insure that they don't change after verification (since
    301       //   the Message interface itself cannot enforce immutability of
    302       //   implementations).
    303       // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
    304       //   which allows people to make secure deep copies of messages.
    305 
    306       for (final Map.Entry<FieldDescriptor, Object> entry :
    307            other.getAllFields().entrySet()) {
    308         final FieldDescriptor field = entry.getKey();
    309         if (field.isRepeated()) {
    310           for (final Object element : (List)entry.getValue()) {
    311             addRepeatedField(field, element);
    312           }
    313         } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
    314           final Message existingValue = (Message)getField(field);
    315           if (existingValue == existingValue.getDefaultInstanceForType()) {
    316             setField(field, entry.getValue());
    317           } else {
    318             setField(field,
    319               existingValue.newBuilderForType()
    320                 .mergeFrom(existingValue)
    321                 .mergeFrom((Message)entry.getValue())
    322                 .build());
    323           }
    324         } else {
    325           setField(field, entry.getValue());
    326         }
    327       }
    328 
    329       mergeUnknownFields(other.getUnknownFields());
    330 
    331       return (BuilderType) this;
    332     }
    333 
    334     @Override
    335     public BuilderType mergeFrom(final CodedInputStream input)
    336                                  throws IOException {
    337       return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
    338     }
    339 
    340     @Override
    341     public BuilderType mergeFrom(
    342         final CodedInputStream input,
    343         final ExtensionRegistryLite extensionRegistry)
    344         throws IOException {
    345       final UnknownFieldSet.Builder unknownFields =
    346         UnknownFieldSet.newBuilder(getUnknownFields());
    347       while (true) {
    348         final int tag = input.readTag();
    349         if (tag == 0) {
    350           break;
    351         }
    352 
    353         if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
    354                             getDescriptorForType(), this, null, tag)) {
    355           // end group tag
    356           break;
    357         }
    358       }
    359       setUnknownFields(unknownFields.build());
    360       return (BuilderType) this;
    361     }
    362 
    363     /** helper method to handle {@code builder} and {@code extensions}. */
    364     private static void addRepeatedField(
    365         Message.Builder builder,
    366         FieldSet<FieldDescriptor> extensions,
    367         FieldDescriptor field,
    368         Object value) {
    369       if (builder != null) {
    370         builder.addRepeatedField(field, value);
    371       } else {
    372         extensions.addRepeatedField(field, value);
    373       }
    374     }
    375 
    376     /** helper method to handle {@code builder} and {@code extensions}. */
    377     private static void setField(
    378         Message.Builder builder,
    379         FieldSet<FieldDescriptor> extensions,
    380         FieldDescriptor field,
    381         Object value) {
    382       if (builder != null) {
    383         builder.setField(field, value);
    384       } else {
    385         extensions.setField(field, value);
    386       }
    387     }
    388 
    389     /** helper method to handle {@code builder} and {@code extensions}. */
    390     private static boolean hasOriginalMessage(
    391         Message.Builder builder,
    392         FieldSet<FieldDescriptor> extensions,
    393         FieldDescriptor field) {
    394       if (builder != null) {
    395         return builder.hasField(field);
    396       } else {
    397         return extensions.hasField(field);
    398       }
    399     }
    400 
    401     /** helper method to handle {@code builder} and {@code extensions}. */
    402     private static Message getOriginalMessage(
    403         Message.Builder builder,
    404         FieldSet<FieldDescriptor> extensions,
    405         FieldDescriptor field) {
    406       if (builder != null) {
    407         return (Message) builder.getField(field);
    408       } else {
    409         return (Message) extensions.getField(field);
    410       }
    411     }
    412 
    413     /** helper method to handle {@code builder} and {@code extensions}. */
    414     private static void mergeOriginalMessage(
    415         Message.Builder builder,
    416         FieldSet<FieldDescriptor> extensions,
    417         FieldDescriptor field,
    418         Message.Builder subBuilder) {
    419       Message originalMessage = getOriginalMessage(builder, extensions, field);
    420       if (originalMessage != null) {
    421         subBuilder.mergeFrom(originalMessage);
    422       }
    423     }
    424 
    425     /**
    426      * Like {@link #mergeFrom(CodedInputStream, ExtensionRegistryLite)}, but
    427      * parses a single field.
    428      *
    429      * When {@code builder} is not null, the method will parse and merge the
    430      * field into {@code builder}. Otherwise, it will try to parse the field
    431      * into {@code extensions}, when it's called by the parsing constructor in
    432      * generated classes.
    433      *
    434      * Package-private because it is used by GeneratedMessage.ExtendableMessage.
    435      * @param tag The tag, which should have already been read.
    436      * @return {@code true} unless the tag is an end-group tag.
    437      */
    438     static boolean mergeFieldFrom(
    439         CodedInputStream input,
    440         UnknownFieldSet.Builder unknownFields,
    441         ExtensionRegistryLite extensionRegistry,
    442         Descriptor type,
    443         Message.Builder builder,
    444         FieldSet<FieldDescriptor> extensions,
    445         int tag) throws IOException {
    446       if (type.getOptions().getMessageSetWireFormat() &&
    447           tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
    448         mergeMessageSetExtensionFromCodedStream(
    449             input, unknownFields, extensionRegistry, type, builder, extensions);
    450         return true;
    451       }
    452 
    453       final int wireType = WireFormat.getTagWireType(tag);
    454       final int fieldNumber = WireFormat.getTagFieldNumber(tag);
    455 
    456       final FieldDescriptor field;
    457       Message defaultInstance = null;
    458 
    459       if (type.isExtensionNumber(fieldNumber)) {
    460         // extensionRegistry may be either ExtensionRegistry or
    461         // ExtensionRegistryLite.  Since the type we are parsing is a full
    462         // message, only a full ExtensionRegistry could possibly contain
    463         // extensions of it.  Otherwise we will treat the registry as if it
    464         // were empty.
    465         if (extensionRegistry instanceof ExtensionRegistry) {
    466           final ExtensionRegistry.ExtensionInfo extension =
    467             ((ExtensionRegistry) extensionRegistry)
    468               .findExtensionByNumber(type, fieldNumber);
    469           if (extension == null) {
    470             field = null;
    471           } else {
    472             field = extension.descriptor;
    473             defaultInstance = extension.defaultInstance;
    474             if (defaultInstance == null &&
    475                 field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
    476               throw new IllegalStateException(
    477                   "Message-typed extension lacked default instance: " +
    478                   field.getFullName());
    479             }
    480           }
    481         } else {
    482           field = null;
    483         }
    484       } else if (builder != null) {
    485         field = type.findFieldByNumber(fieldNumber);
    486       } else {
    487         field = null;
    488       }
    489 
    490       boolean unknown = false;
    491       boolean packed = false;
    492       if (field == null) {
    493         unknown = true;  // Unknown field.
    494       } else if (wireType == FieldSet.getWireFormatForFieldType(
    495                    field.getLiteType(),
    496                    false  /* isPacked */)) {
    497         packed = false;
    498       } else if (field.isPackable() &&
    499                  wireType == FieldSet.getWireFormatForFieldType(
    500                    field.getLiteType(),
    501                    true  /* isPacked */)) {
    502         packed = true;
    503       } else {
    504         unknown = true;  // Unknown wire type.
    505       }
    506 
    507       if (unknown) {  // Unknown field or wrong wire type.  Skip.
    508         return unknownFields.mergeFieldFrom(tag, input);
    509       }
    510 
    511       if (packed) {
    512         final int length = input.readRawVarint32();
    513         final int limit = input.pushLimit(length);
    514         if (field.getLiteType() == WireFormat.FieldType.ENUM) {
    515           while (input.getBytesUntilLimit() > 0) {
    516             final int rawValue = input.readEnum();
    517             final Object value = field.getEnumType().findValueByNumber(rawValue);
    518             if (value == null) {
    519               // If the number isn't recognized as a valid value for this
    520               // enum, drop it (don't even add it to unknownFields).
    521               return true;
    522             }
    523             addRepeatedField(builder, extensions, field, value);
    524           }
    525         } else {
    526           while (input.getBytesUntilLimit() > 0) {
    527             final Object value =
    528               FieldSet.readPrimitiveField(input, field.getLiteType());
    529             addRepeatedField(builder, extensions, field, value);
    530           }
    531         }
    532         input.popLimit(limit);
    533       } else {
    534         final Object value;
    535         switch (field.getType()) {
    536           case GROUP: {
    537             final Message.Builder subBuilder;
    538             if (defaultInstance != null) {
    539               subBuilder = defaultInstance.newBuilderForType();
    540             } else {
    541               subBuilder = builder.newBuilderForField(field);
    542             }
    543             if (!field.isRepeated()) {
    544               mergeOriginalMessage(builder, extensions, field, subBuilder);
    545             }
    546             input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
    547             value = subBuilder.buildPartial();
    548             break;
    549           }
    550           case MESSAGE: {
    551             final Message.Builder subBuilder;
    552             if (defaultInstance != null) {
    553               subBuilder = defaultInstance.newBuilderForType();
    554             } else {
    555               subBuilder = builder.newBuilderForField(field);
    556             }
    557             if (!field.isRepeated()) {
    558               mergeOriginalMessage(builder, extensions, field, subBuilder);
    559             }
    560             input.readMessage(subBuilder, extensionRegistry);
    561             value = subBuilder.buildPartial();
    562             break;
    563           }
    564           case ENUM:
    565             final int rawValue = input.readEnum();
    566             value = field.getEnumType().findValueByNumber(rawValue);
    567             // If the number isn't recognized as a valid value for this enum,
    568             // drop it.
    569             if (value == null) {
    570               unknownFields.mergeVarintField(fieldNumber, rawValue);
    571               return true;
    572             }
    573             break;
    574           default:
    575             value = FieldSet.readPrimitiveField(input, field.getLiteType());
    576             break;
    577         }
    578 
    579         if (field.isRepeated()) {
    580           addRepeatedField(builder, extensions, field, value);
    581         } else {
    582           setField(builder, extensions, field, value);
    583         }
    584       }
    585 
    586       return true;
    587     }
    588 
    589     /**
    590      * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension.
    591      * If {@code builder} is not null, this method will merge MessageSet into
    592      * the builder.  Otherwise, it will merge the MessageSet into {@code
    593      * extensions}.
    594      */
    595     private static void mergeMessageSetExtensionFromCodedStream(
    596         CodedInputStream input,
    597         UnknownFieldSet.Builder unknownFields,
    598         ExtensionRegistryLite extensionRegistry,
    599         Descriptor type,
    600         Message.Builder builder,
    601         FieldSet<FieldDescriptor> extensions) throws IOException {
    602 
    603       // The wire format for MessageSet is:
    604       //   message MessageSet {
    605       //     repeated group Item = 1 {
    606       //       required int32 typeId = 2;
    607       //       required bytes message = 3;
    608       //     }
    609       //   }
    610       // "typeId" is the extension's field number.  The extension can only be
    611       // a message type, where "message" contains the encoded bytes of that
    612       // message.
    613       //
    614       // In practice, we will probably never see a MessageSet item in which
    615       // the message appears before the type ID, or where either field does not
    616       // appear exactly once.  However, in theory such cases are valid, so we
    617       // should be prepared to accept them.
    618 
    619       int typeId = 0;
    620       ByteString rawBytes = null; // If we encounter "message" before "typeId"
    621       ExtensionRegistry.ExtensionInfo extension = null;
    622 
    623       // Read bytes from input, if we get it's type first then parse it eagerly,
    624       // otherwise we store the raw bytes in a local variable.
    625       while (true) {
    626         final int tag = input.readTag();
    627         if (tag == 0) {
    628           break;
    629         }
    630 
    631         if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
    632           typeId = input.readUInt32();
    633           if (typeId != 0) {
    634             // extensionRegistry may be either ExtensionRegistry or
    635             // ExtensionRegistryLite. Since the type we are parsing is a full
    636             // message, only a full ExtensionRegistry could possibly contain
    637             // extensions of it. Otherwise we will treat the registry as if it
    638             // were empty.
    639             if (extensionRegistry instanceof ExtensionRegistry) {
    640               extension = ((ExtensionRegistry) extensionRegistry)
    641                   .findExtensionByNumber(type, typeId);
    642             }
    643           }
    644 
    645         } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
    646           if (typeId != 0) {
    647             if (extension != null && ExtensionRegistryLite.isEagerlyParseMessageSets()) {
    648               // We already know the type, so we can parse directly from the
    649               // input with no copying.  Hooray!
    650               eagerlyMergeMessageSetExtension(
    651                   input, extension, extensionRegistry, builder, extensions);
    652               rawBytes = null;
    653               continue;
    654             }
    655           }
    656           // We haven't seen a type ID yet or we want parse message lazily.
    657           rawBytes = input.readBytes();
    658 
    659         } else { // Unknown tag. Skip it.
    660           if (!input.skipField(tag)) {
    661             break; // End of group
    662           }
    663         }
    664       }
    665       input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
    666 
    667       // Process the raw bytes.
    668       if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
    669         if (extension != null) { // We known the type
    670           mergeMessageSetExtensionFromBytes(
    671               rawBytes, extension, extensionRegistry, builder, extensions);
    672         } else { // We don't know how to parse this. Ignore it.
    673           if (rawBytes != null) {
    674             unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
    675                 .addLengthDelimited(rawBytes).build());
    676           }
    677         }
    678       }
    679     }
    680 
    681     private static void eagerlyMergeMessageSetExtension(
    682         CodedInputStream input,
    683         ExtensionRegistry.ExtensionInfo extension,
    684         ExtensionRegistryLite extensionRegistry,
    685         Message.Builder builder,
    686         FieldSet<FieldDescriptor> extensions) throws IOException {
    687 
    688       FieldDescriptor field = extension.descriptor;
    689       Message value = null;
    690       if (hasOriginalMessage(builder, extensions, field)) {
    691         Message originalMessage =
    692             getOriginalMessage(builder, extensions, field);
    693         Message.Builder subBuilder = originalMessage.toBuilder();
    694         input.readMessage(subBuilder, extensionRegistry);
    695         value = subBuilder.buildPartial();
    696       } else {
    697         value = input.readMessage(extension.defaultInstance.getParserForType(),
    698           extensionRegistry);
    699       }
    700 
    701       if (builder != null) {
    702         builder.setField(field, value);
    703       } else {
    704         extensions.setField(field, value);
    705       }
    706     }
    707 
    708     private static void mergeMessageSetExtensionFromBytes(
    709         ByteString rawBytes,
    710         ExtensionRegistry.ExtensionInfo extension,
    711         ExtensionRegistryLite extensionRegistry,
    712         Message.Builder builder,
    713         FieldSet<FieldDescriptor> extensions) throws IOException {
    714 
    715       FieldDescriptor field = extension.descriptor;
    716       boolean hasOriginalValue = hasOriginalMessage(builder, extensions, field);
    717 
    718       if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
    719         // If the field already exists, we just parse the field.
    720         Message value = null;
    721         if (hasOriginalValue) {
    722           Message originalMessage =
    723               getOriginalMessage(builder, extensions, field);
    724           Message.Builder subBuilder= originalMessage.toBuilder();
    725           subBuilder.mergeFrom(rawBytes, extensionRegistry);
    726           value = subBuilder.buildPartial();
    727         } else {
    728           value = extension.defaultInstance.getParserForType()
    729               .parsePartialFrom(rawBytes, extensionRegistry);
    730         }
    731         setField(builder, extensions, field, value);
    732       } else {
    733         // Use LazyField to load MessageSet lazily.
    734         LazyField lazyField = new LazyField(
    735             extension.defaultInstance, extensionRegistry, rawBytes);
    736         if (builder != null) {
    737           // TODO(xiangl): it looks like this method can only be invoked by
    738           // ExtendableBuilder, but I'm not sure. So I double check the type of
    739           // builder here. It may be useless and need more investigation.
    740           if (builder instanceof ExtendableBuilder) {
    741             builder.setField(field, lazyField);
    742           } else {
    743             builder.setField(field, lazyField.getValue());
    744           }
    745         } else {
    746           extensions.setField(field, lazyField);
    747         }
    748       }
    749     }
    750 
    751     public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
    752       setUnknownFields(
    753         UnknownFieldSet.newBuilder(getUnknownFields())
    754                        .mergeFrom(unknownFields)
    755                        .build());
    756       return (BuilderType) this;
    757     }
    758 
    759     public Message.Builder getFieldBuilder(final FieldDescriptor field) {
    760       throw new UnsupportedOperationException(
    761           "getFieldBuilder() called on an unsupported message type.");
    762     }
    763 
    764     /**
    765      * Construct an UninitializedMessageException reporting missing fields in
    766      * the given message.
    767      */
    768     protected static UninitializedMessageException
    769         newUninitializedMessageException(Message message) {
    770       return new UninitializedMessageException(findMissingFields(message));
    771     }
    772 
    773     /**
    774      * Populates {@code this.missingFields} with the full "path" of each
    775      * missing required field in the given message.
    776      */
    777     private static List<String> findMissingFields(
    778         final MessageOrBuilder message) {
    779       final List<String> results = new ArrayList<String>();
    780       findMissingFields(message, "", results);
    781       return results;
    782     }
    783 
    784     /** Recursive helper implementing {@link #findMissingFields(Message)}. */
    785     private static void findMissingFields(final MessageOrBuilder message,
    786                                           final String prefix,
    787                                           final List<String> results) {
    788       for (final FieldDescriptor field :
    789           message.getDescriptorForType().getFields()) {
    790         if (field.isRequired() && !message.hasField(field)) {
    791           results.add(prefix + field.getName());
    792         }
    793       }
    794 
    795       for (final Map.Entry<FieldDescriptor, Object> entry :
    796            message.getAllFields().entrySet()) {
    797         final FieldDescriptor field = entry.getKey();
    798         final Object value = entry.getValue();
    799 
    800         if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
    801           if (field.isRepeated()) {
    802             int i = 0;
    803             for (final Object element : (List) value) {
    804               findMissingFields((MessageOrBuilder) element,
    805                                 subMessagePrefix(prefix, field, i++),
    806                                 results);
    807             }
    808           } else {
    809             if (message.hasField(field)) {
    810               findMissingFields((MessageOrBuilder) value,
    811                                 subMessagePrefix(prefix, field, -1),
    812                                 results);
    813             }
    814           }
    815         }
    816       }
    817     }
    818 
    819     private static String subMessagePrefix(final String prefix,
    820                                            final FieldDescriptor field,
    821                                            final int index) {
    822       final StringBuilder result = new StringBuilder(prefix);
    823       if (field.isExtension()) {
    824         result.append('(')
    825               .append(field.getFullName())
    826               .append(')');
    827       } else {
    828         result.append(field.getName());
    829       }
    830       if (index != -1) {
    831         result.append('[')
    832               .append(index)
    833               .append(']');
    834       }
    835       result.append('.');
    836       return result.toString();
    837     }
    838 
    839     // ===============================================================
    840     // The following definitions seem to be required in order to make javac
    841     // not produce weird errors like:
    842     //
    843     // java/com/google/protobuf/DynamicMessage.java:203: types
    844     //   com.google.protobuf.AbstractMessage.Builder<
    845     //     com.google.protobuf.DynamicMessage.Builder> and
    846     //   com.google.protobuf.AbstractMessage.Builder<
    847     //     com.google.protobuf.DynamicMessage.Builder> are incompatible; both
    848     //   define mergeFrom(com.google.protobuf.ByteString), but with unrelated
    849     //   return types.
    850     //
    851     // Strangely, these lines are only needed if javac is invoked separately
    852     // on AbstractMessage.java and AbstractMessageLite.java.  If javac is
    853     // invoked on both simultaneously, it works.  (Or maybe the important
    854     // point is whether or not DynamicMessage.java is compiled together with
    855     // AbstractMessageLite.java -- not sure.)  I suspect this is a compiler
    856     // bug.
    857 
    858     @Override
    859     public BuilderType mergeFrom(final ByteString data)
    860         throws InvalidProtocolBufferException {
    861       return super.mergeFrom(data);
    862     }
    863 
    864     @Override
    865     public BuilderType mergeFrom(
    866         final ByteString data,
    867         final ExtensionRegistryLite extensionRegistry)
    868         throws InvalidProtocolBufferException {
    869       return super.mergeFrom(data, extensionRegistry);
    870     }
    871 
    872     @Override
    873     public BuilderType mergeFrom(final byte[] data)
    874         throws InvalidProtocolBufferException {
    875       return super.mergeFrom(data);
    876     }
    877 
    878     @Override
    879     public BuilderType mergeFrom(
    880         final byte[] data, final int off, final int len)
    881         throws InvalidProtocolBufferException {
    882       return super.mergeFrom(data, off, len);
    883     }
    884 
    885     @Override
    886     public BuilderType mergeFrom(
    887         final byte[] data,
    888         final ExtensionRegistryLite extensionRegistry)
    889         throws InvalidProtocolBufferException {
    890       return super.mergeFrom(data, extensionRegistry);
    891     }
    892 
    893     @Override
    894     public BuilderType mergeFrom(
    895         final byte[] data, final int off, final int len,
    896         final ExtensionRegistryLite extensionRegistry)
    897         throws InvalidProtocolBufferException {
    898       return super.mergeFrom(data, off, len, extensionRegistry);
    899     }
    900 
    901     @Override
    902     public BuilderType mergeFrom(final InputStream input)
    903         throws IOException {
    904       return super.mergeFrom(input);
    905     }
    906 
    907     @Override
    908     public BuilderType mergeFrom(
    909         final InputStream input,
    910         final ExtensionRegistryLite extensionRegistry)
    911         throws IOException {
    912       return super.mergeFrom(input, extensionRegistry);
    913     }
    914 
    915     @Override
    916     public boolean mergeDelimitedFrom(final InputStream input)
    917         throws IOException {
    918       return super.mergeDelimitedFrom(input);
    919     }
    920 
    921     @Override
    922     public boolean mergeDelimitedFrom(
    923         final InputStream input,
    924         final ExtensionRegistryLite extensionRegistry)
    925         throws IOException {
    926       return super.mergeDelimitedFrom(input, extensionRegistry);
    927     }
    928 
    929   }
    930 }
    931