Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
87 Kevin 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.Internal.EnumLite;
36
 
37
import java.io.IOException;
38
import java.io.InputStream;
39
import java.util.ArrayList;
40
import java.util.List;
41
import java.util.Map;
42
 
43
/**
44
 * A partial implementation of the {@link Message} interface which implements
45
 * as many methods of that interface as possible in terms of other methods.
46
 *
47
 * @author kenton@google.com Kenton Varda
48
 */
49
public abstract class AbstractMessage extends AbstractMessageLite
50
                                      implements Message {
51
  @SuppressWarnings("unchecked")
52
  public boolean isInitialized() {
53
    // Check that all required fields are present.
54
    for (final FieldDescriptor field : getDescriptorForType().getFields()) {
55
      if (field.isRequired()) {
56
        if (!hasField(field)) {
57
          return false;
58
        }
59
      }
60
    }
61
 
62
    // Check that embedded messages are initialized.
63
    for (final Map.Entry<FieldDescriptor, Object> entry :
64
        getAllFields().entrySet()) {
65
      final FieldDescriptor field = entry.getKey();
66
      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
67
        if (field.isRepeated()) {
68
          for (final Message element : (List<Message>) entry.getValue()) {
69
            if (!element.isInitialized()) {
70
              return false;
71
            }
72
          }
73
        } else {
74
          if (!((Message) entry.getValue()).isInitialized()) {
75
            return false;
76
          }
77
        }
78
      }
79
    }
80
 
81
    return true;
82
  }
83
 
84
  @Override
85
  public final String toString() {
86
    return TextFormat.printToString(this);
87
  }
88
 
89
  public void writeTo(final CodedOutputStream output) throws IOException {
90
    final boolean isMessageSet =
91
        getDescriptorForType().getOptions().getMessageSetWireFormat();
92
 
93
    for (final Map.Entry<FieldDescriptor, Object> entry :
94
        getAllFields().entrySet()) {
95
      final FieldDescriptor field = entry.getKey();
96
      final Object value = entry.getValue();
97
      if (isMessageSet && field.isExtension() &&
98
          field.getType() == FieldDescriptor.Type.MESSAGE &&
99
          !field.isRepeated()) {
100
        output.writeMessageSetExtension(field.getNumber(), (Message) value);
101
      } else {
102
        FieldSet.writeField(field, value, output);
103
      }
104
    }
105
 
106
    final UnknownFieldSet unknownFields = getUnknownFields();
107
    if (isMessageSet) {
108
      unknownFields.writeAsMessageSetTo(output);
109
    } else {
110
      unknownFields.writeTo(output);
111
    }
112
  }
113
 
114
  private int memoizedSize = -1;
115
 
116
  public int getSerializedSize() {
117
    int size = memoizedSize;
118
    if (size != -1) {
119
      return size;
120
    }
121
 
122
    size = 0;
123
    final boolean isMessageSet =
124
        getDescriptorForType().getOptions().getMessageSetWireFormat();
125
 
126
    for (final Map.Entry<FieldDescriptor, Object> entry :
127
        getAllFields().entrySet()) {
128
      final FieldDescriptor field = entry.getKey();
129
      final Object value = entry.getValue();
130
      if (isMessageSet && field.isExtension() &&
131
          field.getType() == FieldDescriptor.Type.MESSAGE &&
132
          !field.isRepeated()) {
133
        size += CodedOutputStream.computeMessageSetExtensionSize(
134
            field.getNumber(), (Message) value);
135
      } else {
136
        size += FieldSet.computeFieldSize(field, value);
137
      }
138
    }
139
 
140
    final UnknownFieldSet unknownFields = getUnknownFields();
141
    if (isMessageSet) {
142
      size += unknownFields.getSerializedSizeAsMessageSet();
143
    } else {
144
      size += unknownFields.getSerializedSize();
145
    }
146
 
147
    memoizedSize = size;
148
    return size;
149
  }
150
 
151
  @Override
152
  public boolean equals(final Object other) {
153
    if (other == this) {
154
      return true;
155
    }
156
    if (!(other instanceof Message)) {
157
      return false;
158
    }
159
    final Message otherMessage = (Message) other;
160
    if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
161
      return false;
162
    }
163
    return getAllFields().equals(otherMessage.getAllFields()) &&
164
        getUnknownFields().equals(otherMessage.getUnknownFields());
165
  }
166
 
167
  @Override
168
  public int hashCode() {
169
    int hash = 41;
170
    hash = (19 * hash) + getDescriptorForType().hashCode();
171
    hash = hashFields(hash, getAllFields());
172
    hash = (29 * hash) + getUnknownFields().hashCode();
173
    return hash;
174
  }
175
 
176
  /** Get a hash code for given fields and values, using the given seed. */
177
  @SuppressWarnings("unchecked")
178
  protected int hashFields(int hash, Map<FieldDescriptor, Object> map) {
179
    for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
180
      FieldDescriptor field = entry.getKey();
181
      Object value = entry.getValue();
182
      hash = (37 * hash) + field.getNumber();
183
      if (field.getType() != FieldDescriptor.Type.ENUM){
184
        hash = (53 * hash) + value.hashCode();
185
      } else if (field.isRepeated()) {
186
        List<? extends EnumLite> list = (List<? extends EnumLite>) value;
187
        hash = (53 * hash) + hashEnumList(list);
188
      } else {
189
        hash = (53 * hash) + hashEnum((EnumLite) value);
190
      }
191
    }
192
    return hash;
193
  }
194
 
195
  /**
196
   * Helper method for implementing {@link Message#hashCode()}.
197
   * @see Boolean#hashCode()
198
   */
199
  protected static int hashLong(long n) {
200
    return (int) (n ^ (n >>> 32));
201
  }
202
 
203
  /**
204
   * Helper method for implementing {@link Message#hashCode()}.
205
   * @see Boolean#hashCode()
206
   */
207
  protected static int hashBoolean(boolean b) {
208
    return b ? 1231 : 1237;
209
  }
210
 
211
  /**
212
   * Helper method for implementing {@link Message#hashCode()}.
213
   * <p>
214
   * This is needed because {@link java.lang.Enum#hashCode()} is final, but we
215
   * need to use the field number as the hash code to ensure compatibility
216
   * between statically and dynamically generated enum objects.
217
   */
218
  protected static int hashEnum(EnumLite e) {
219
    return e.getNumber();
220
  }
221
 
222
  /** Helper method for implementing {@link Message#hashCode()}. */
223
  protected static int hashEnumList(List<? extends EnumLite> list) {
224
    int hash = 1;
225
    for (EnumLite e : list) {
226
      hash = 31 * hash + hashEnum(e);
227
    }
228
    return hash;
229
  }
230
 
231
  // =================================================================
232
 
233
  /**
234
   * A partial implementation of the {@link Message.Builder} interface which
235
   * implements as many methods of that interface as possible in terms of
236
   * other methods.
237
   */
238
  @SuppressWarnings("unchecked")
239
  public static abstract class Builder<BuilderType extends Builder>
240
      extends AbstractMessageLite.Builder<BuilderType>
241
      implements Message.Builder {
242
    // The compiler produces an error if this is not declared explicitly.
243
    @Override
244
    public abstract BuilderType clone();
245
 
246
    public BuilderType clear() {
247
      for (final Map.Entry<FieldDescriptor, Object> entry :
248
           getAllFields().entrySet()) {
249
        clearField(entry.getKey());
250
      }
251
      return (BuilderType) this;
252
    }
253
 
254
    public BuilderType mergeFrom(final Message other) {
255
      if (other.getDescriptorForType() != getDescriptorForType()) {
256
        throw new IllegalArgumentException(
257
          "mergeFrom(Message) can only merge messages of the same type.");
258
      }
259
 
260
      // Note:  We don't attempt to verify that other's fields have valid
261
      //   types.  Doing so would be a losing battle.  We'd have to verify
262
      //   all sub-messages as well, and we'd have to make copies of all of
263
      //   them to insure that they don't change after verification (since
264
      //   the Message interface itself cannot enforce immutability of
265
      //   implementations).
266
      // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
267
      //   which allows people to make secure deep copies of messages.
268
 
269
      for (final Map.Entry<FieldDescriptor, Object> entry :
270
           other.getAllFields().entrySet()) {
271
        final FieldDescriptor field = entry.getKey();
272
        if (field.isRepeated()) {
273
          for (final Object element : (List)entry.getValue()) {
274
            addRepeatedField(field, element);
275
          }
276
        } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
277
          final Message existingValue = (Message)getField(field);
278
          if (existingValue == existingValue.getDefaultInstanceForType()) {
279
            setField(field, entry.getValue());
280
          } else {
281
            setField(field,
282
              existingValue.newBuilderForType()
283
                .mergeFrom(existingValue)
284
                .mergeFrom((Message)entry.getValue())
285
                .build());
286
          }
287
        } else {
288
          setField(field, entry.getValue());
289
        }
290
      }
291
 
292
      mergeUnknownFields(other.getUnknownFields());
293
 
294
      return (BuilderType) this;
295
    }
296
 
297
    @Override
298
    public BuilderType mergeFrom(final CodedInputStream input)
299
                                 throws IOException {
300
      return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
301
    }
302
 
303
    @Override
304
    public BuilderType mergeFrom(
305
        final CodedInputStream input,
306
        final ExtensionRegistryLite extensionRegistry)
307
        throws IOException {
308
      final UnknownFieldSet.Builder unknownFields =
309
        UnknownFieldSet.newBuilder(getUnknownFields());
310
      while (true) {
311
        final int tag = input.readTag();
312
        if (tag == 0) {
313
          break;
314
        }
315
 
316
        if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
317
                            this, tag)) {
318
          // end group tag
319
          break;
320
        }
321
      }
322
      setUnknownFields(unknownFields.build());
323
      return (BuilderType) this;
324
    }
325
 
326
    /**
327
     * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
328
     * ExtensionRegistryLite, Message.Builder)}, but parses a single field.
329
     * Package-private because it is used by GeneratedMessage.ExtendableMessage.
330
     * @param tag The tag, which should have already been read.
331
     * @return {@code true} unless the tag is an end-group tag.
332
     */
333
    static boolean mergeFieldFrom(
334
        final CodedInputStream input,
335
        final UnknownFieldSet.Builder unknownFields,
336
        final ExtensionRegistryLite extensionRegistry,
337
        final Message.Builder builder,
338
        final int tag) throws IOException {
339
      final Descriptor type = builder.getDescriptorForType();
340
 
341
      if (type.getOptions().getMessageSetWireFormat() &&
342
          tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
343
        mergeMessageSetExtensionFromCodedStream(
344
          input, unknownFields, extensionRegistry, builder);
345
        return true;
346
      }
347
 
348
      final int wireType = WireFormat.getTagWireType(tag);
349
      final int fieldNumber = WireFormat.getTagFieldNumber(tag);
350
 
351
      final FieldDescriptor field;
352
      Message defaultInstance = null;
353
 
354
      if (type.isExtensionNumber(fieldNumber)) {
355
        // extensionRegistry may be either ExtensionRegistry or
356
        // ExtensionRegistryLite.  Since the type we are parsing is a full
357
        // message, only a full ExtensionRegistry could possibly contain
358
        // extensions of it.  Otherwise we will treat the registry as if it
359
        // were empty.
360
        if (extensionRegistry instanceof ExtensionRegistry) {
361
          final ExtensionRegistry.ExtensionInfo extension =
362
            ((ExtensionRegistry) extensionRegistry)
363
              .findExtensionByNumber(type, fieldNumber);
364
          if (extension == null) {
365
            field = null;
366
          } else {
367
            field = extension.descriptor;
368
            defaultInstance = extension.defaultInstance;
369
            if (defaultInstance == null &&
370
                field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
371
              throw new IllegalStateException(
372
                  "Message-typed extension lacked default instance: " +
373
                  field.getFullName());
374
            }
375
          }
376
        } else {
377
          field = null;
378
        }
379
      } else {
380
        field = type.findFieldByNumber(fieldNumber);
381
      }
382
 
383
      boolean unknown = false;
384
      boolean packed = false;
385
      if (field == null) {
386
        unknown = true;  // Unknown field.
387
      } else if (wireType == FieldSet.getWireFormatForFieldType(
388
                   field.getLiteType(),
389
                   false  /* isPacked */)) {
390
        packed = false;
391
      } else if (field.isPackable() &&
392
                 wireType == FieldSet.getWireFormatForFieldType(
393
                   field.getLiteType(),
394
                   true  /* isPacked */)) {
395
        packed = true;
396
      } else {
397
        unknown = true;  // Unknown wire type.
398
      }
399
 
400
      if (unknown) {  // Unknown field or wrong wire type.  Skip.
401
        return unknownFields.mergeFieldFrom(tag, input);
402
      }
403
 
404
      if (packed) {
405
        final int length = input.readRawVarint32();
406
        final int limit = input.pushLimit(length);
407
        if (field.getLiteType() == WireFormat.FieldType.ENUM) {
408
          while (input.getBytesUntilLimit() > 0) {
409
            final int rawValue = input.readEnum();
410
            final Object value = field.getEnumType().findValueByNumber(rawValue);
411
            if (value == null) {
412
              // If the number isn't recognized as a valid value for this
413
              // enum, drop it (don't even add it to unknownFields).
414
              return true;
415
            }
416
            builder.addRepeatedField(field, value);
417
          }
418
        } else {
419
          while (input.getBytesUntilLimit() > 0) {
420
            final Object value =
421
              FieldSet.readPrimitiveField(input, field.getLiteType());
422
            builder.addRepeatedField(field, value);
423
          }
424
        }
425
        input.popLimit(limit);
426
      } else {
427
        final Object value;
428
        switch (field.getType()) {
429
          case GROUP: {
430
            final Message.Builder subBuilder;
431
            if (defaultInstance != null) {
432
              subBuilder = defaultInstance.newBuilderForType();
433
            } else {
434
              subBuilder = builder.newBuilderForField(field);
435
            }
436
            if (!field.isRepeated()) {
437
              subBuilder.mergeFrom((Message) builder.getField(field));
438
            }
439
            input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
440
            value = subBuilder.build();
441
            break;
442
          }
443
          case MESSAGE: {
444
            final Message.Builder subBuilder;
445
            if (defaultInstance != null) {
446
              subBuilder = defaultInstance.newBuilderForType();
447
            } else {
448
              subBuilder = builder.newBuilderForField(field);
449
            }
450
            if (!field.isRepeated()) {
451
              subBuilder.mergeFrom((Message) builder.getField(field));
452
            }
453
            input.readMessage(subBuilder, extensionRegistry);
454
            value = subBuilder.build();
455
            break;
456
          }
457
          case ENUM:
458
            final int rawValue = input.readEnum();
459
            value = field.getEnumType().findValueByNumber(rawValue);
460
            // If the number isn't recognized as a valid value for this enum,
461
            // drop it.
462
            if (value == null) {
463
              unknownFields.mergeVarintField(fieldNumber, rawValue);
464
              return true;
465
            }
466
            break;
467
          default:
468
            value = FieldSet.readPrimitiveField(input, field.getLiteType());
469
            break;
470
        }
471
 
472
        if (field.isRepeated()) {
473
          builder.addRepeatedField(field, value);
474
        } else {
475
          builder.setField(field, value);
476
        }
477
      }
478
 
479
      return true;
480
    }
481
 
482
    /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
483
    private static void mergeMessageSetExtensionFromCodedStream(
484
        final CodedInputStream input,
485
        final UnknownFieldSet.Builder unknownFields,
486
        final ExtensionRegistryLite extensionRegistry,
487
        final Message.Builder builder) throws IOException {
488
      final Descriptor type = builder.getDescriptorForType();
489
 
490
      // The wire format for MessageSet is:
491
      //   message MessageSet {
492
      //     repeated group Item = 1 {
493
      //       required int32 typeId = 2;
494
      //       required bytes message = 3;
495
      //     }
496
      //   }
497
      // "typeId" is the extension's field number.  The extension can only be
498
      // a message type, where "message" contains the encoded bytes of that
499
      // message.
500
      //
501
      // In practice, we will probably never see a MessageSet item in which
502
      // the message appears before the type ID, or where either field does not
503
      // appear exactly once.  However, in theory such cases are valid, so we
504
      // should be prepared to accept them.
505
 
506
      int typeId = 0;
507
      ByteString rawBytes = null;  // If we encounter "message" before "typeId"
508
      Message.Builder subBuilder = null;
509
      FieldDescriptor field = null;
510
 
511
      while (true) {
512
        final int tag = input.readTag();
513
        if (tag == 0) {
514
          break;
515
        }
516
 
517
        if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
518
          typeId = input.readUInt32();
519
          // Zero is not a valid type ID.
520
          if (typeId != 0) {
521
            final ExtensionRegistry.ExtensionInfo extension;
522
 
523
            // extensionRegistry may be either ExtensionRegistry or
524
            // ExtensionRegistryLite.  Since the type we are parsing is a full
525
            // message, only a full ExtensionRegistry could possibly contain
526
            // extensions of it.  Otherwise we will treat the registry as if it
527
            // were empty.
528
            if (extensionRegistry instanceof ExtensionRegistry) {
529
              extension = ((ExtensionRegistry) extensionRegistry)
530
                  .findExtensionByNumber(type, typeId);
531
            } else {
532
              extension = null;
533
            }
534
 
535
            if (extension != null) {
536
              field = extension.descriptor;
537
              subBuilder = extension.defaultInstance.newBuilderForType();
538
              final Message originalMessage = (Message)builder.getField(field);
539
              if (originalMessage != null) {
540
                subBuilder.mergeFrom(originalMessage);
541
              }
542
              if (rawBytes != null) {
543
                // We already encountered the message.  Parse it now.
544
                subBuilder.mergeFrom(
545
                  CodedInputStream.newInstance(rawBytes.newInput()));
546
                rawBytes = null;
547
              }
548
            } else {
549
              // Unknown extension number.  If we already saw data, put it
550
              // in rawBytes.
551
              if (rawBytes != null) {
552
                unknownFields.mergeField(typeId,
553
                  UnknownFieldSet.Field.newBuilder()
554
                    .addLengthDelimited(rawBytes)
555
                    .build());
556
                rawBytes = null;
557
              }
558
            }
559
          }
560
        } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
561
          if (typeId == 0) {
562
            // We haven't seen a type ID yet, so we have to store the raw bytes
563
            // for now.
564
            rawBytes = input.readBytes();
565
          } else if (subBuilder == null) {
566
            // We don't know how to parse this.  Ignore it.
567
            unknownFields.mergeField(typeId,
568
              UnknownFieldSet.Field.newBuilder()
569
                .addLengthDelimited(input.readBytes())
570
                .build());
571
          } else {
572
            // We already know the type, so we can parse directly from the input
573
            // with no copying.  Hooray!
574
            input.readMessage(subBuilder, extensionRegistry);
575
          }
576
        } else {
577
          // Unknown tag.  Skip it.
578
          if (!input.skipField(tag)) {
579
            break;  // end of group
580
          }
581
        }
582
      }
583
 
584
      input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
585
 
586
      if (subBuilder != null) {
587
        builder.setField(field, subBuilder.build());
588
      }
589
    }
590
 
591
    public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
592
      setUnknownFields(
593
        UnknownFieldSet.newBuilder(getUnknownFields())
594
                       .mergeFrom(unknownFields)
595
                       .build());
596
      return (BuilderType) this;
597
    }
598
 
599
    /**
600
     * Construct an UninitializedMessageException reporting missing fields in
601
     * the given message.
602
     */
603
    protected static UninitializedMessageException
604
        newUninitializedMessageException(Message message) {
605
      return new UninitializedMessageException(findMissingFields(message));
606
    }
607
 
608
    /**
609
     * Populates {@code this.missingFields} with the full "path" of each
610
     * missing required field in the given message.
611
     */
612
    private static List<String> findMissingFields(final Message message) {
613
      final List<String> results = new ArrayList<String>();
614
      findMissingFields(message, "", results);
615
      return results;
616
    }
617
 
618
    /** Recursive helper implementing {@link #findMissingFields(Message)}. */
619
    private static void findMissingFields(final Message message,
620
                                          final String prefix,
621
                                          final List<String> results) {
622
      for (final FieldDescriptor field :
623
          message.getDescriptorForType().getFields()) {
624
        if (field.isRequired() && !message.hasField(field)) {
625
          results.add(prefix + field.getName());
626
        }
627
      }
628
 
629
      for (final Map.Entry<FieldDescriptor, Object> entry :
630
           message.getAllFields().entrySet()) {
631
        final FieldDescriptor field = entry.getKey();
632
        final Object value = entry.getValue();
633
 
634
        if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
635
          if (field.isRepeated()) {
636
            int i = 0;
637
            for (final Object element : (List) value) {
638
              findMissingFields((Message) element,
639
                                subMessagePrefix(prefix, field, i++),
640
                                results);
641
            }
642
          } else {
643
            if (message.hasField(field)) {
644
              findMissingFields((Message) value,
645
                                subMessagePrefix(prefix, field, -1),
646
                                results);
647
            }
648
          }
649
        }
650
      }
651
    }
652
 
653
    private static String subMessagePrefix(final String prefix,
654
                                           final FieldDescriptor field,
655
                                           final int index) {
656
      final StringBuilder result = new StringBuilder(prefix);
657
      if (field.isExtension()) {
658
        result.append('(')
659
              .append(field.getFullName())
660
              .append(')');
661
      } else {
662
        result.append(field.getName());
663
      }
664
      if (index != -1) {
665
        result.append('[')
666
              .append(index)
667
              .append(']');
668
      }
669
      result.append('.');
670
      return result.toString();
671
    }
672
 
673
    // ===============================================================
674
    // The following definitions seem to be required in order to make javac
675
    // not produce weird errors like:
676
    //
677
    // java/com/google/protobuf/DynamicMessage.java:203: types
678
    //   com.google.protobuf.AbstractMessage.Builder<
679
    //     com.google.protobuf.DynamicMessage.Builder> and
680
    //   com.google.protobuf.AbstractMessage.Builder<
681
    //     com.google.protobuf.DynamicMessage.Builder> are incompatible; both
682
    //   define mergeFrom(com.google.protobuf.ByteString), but with unrelated
683
    //   return types.
684
    //
685
    // Strangely, these lines are only needed if javac is invoked separately
686
    // on AbstractMessage.java and AbstractMessageLite.java.  If javac is
687
    // invoked on both simultaneously, it works.  (Or maybe the important
688
    // point is whether or not DynamicMessage.java is compiled together with
689
    // AbstractMessageLite.java -- not sure.)  I suspect this is a compiler
690
    // bug.
691
 
692
    @Override
693
    public BuilderType mergeFrom(final ByteString data)
694
        throws InvalidProtocolBufferException {
695
      return super.mergeFrom(data);
696
    }
697
 
698
    @Override
699
    public BuilderType mergeFrom(
700
        final ByteString data,
701
        final ExtensionRegistryLite extensionRegistry)
702
        throws InvalidProtocolBufferException {
703
      return super.mergeFrom(data, extensionRegistry);
704
    }
705
 
706
    @Override
707
    public BuilderType mergeFrom(final byte[] data)
708
        throws InvalidProtocolBufferException {
709
      return super.mergeFrom(data);
710
    }
711
 
712
    @Override
713
    public BuilderType mergeFrom(
714
        final byte[] data, final int off, final int len)
715
        throws InvalidProtocolBufferException {
716
      return super.mergeFrom(data, off, len);
717
    }
718
 
719
    @Override
720
    public BuilderType mergeFrom(
721
        final byte[] data,
722
        final ExtensionRegistryLite extensionRegistry)
723
        throws InvalidProtocolBufferException {
724
      return super.mergeFrom(data, extensionRegistry);
725
    }
726
 
727
    @Override
728
    public BuilderType mergeFrom(
729
        final byte[] data, final int off, final int len,
730
        final ExtensionRegistryLite extensionRegistry)
731
        throws InvalidProtocolBufferException {
732
      return super.mergeFrom(data, off, len, extensionRegistry);
733
    }
734
 
735
    @Override
736
    public BuilderType mergeFrom(final InputStream input)
737
        throws IOException {
738
      return super.mergeFrom(input);
739
    }
740
 
741
    @Override
742
    public BuilderType mergeFrom(
743
        final InputStream input,
744
        final ExtensionRegistryLite extensionRegistry)
745
        throws IOException {
746
      return super.mergeFrom(input, extensionRegistry);
747
    }
748
 
749
    @Override
750
    public boolean mergeDelimitedFrom(final InputStream input)
751
        throws IOException {
752
      return super.mergeDelimitedFrom(input);
753
    }
754
 
755
    @Override
756
    public boolean mergeDelimitedFrom(
757
        final InputStream input,
758
        final ExtensionRegistryLite extensionRegistry)
759
        throws IOException {
760
      return super.mergeDelimitedFrom(input, extensionRegistry);
761
    }
762
 
763
  }
764
}