• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
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 static com.google.protobuf.Internal.checkNotNull;
34 
35 import com.google.protobuf.LazyField.LazyIterator;
36 import java.io.IOException;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 
43 /**
44  * A class which represents an arbitrary set of fields of some message type. This is used to
45  * implement {@link DynamicMessage}, and also to represent extensions in {@link GeneratedMessage}.
46  * This class is package-private, since outside users should probably be using {@link
47  * DynamicMessage}.
48  *
49  * @author kenton@google.com Kenton Varda
50  */
51 final class FieldSet<T extends FieldSet.FieldDescriptorLite<T>> {
52   /**
53    * Interface for a FieldDescriptor or lite extension descriptor. This prevents FieldSet from
54    * depending on {@link Descriptors.FieldDescriptor}.
55    */
56   public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>> extends Comparable<T> {
getNumber()57     int getNumber();
58 
getLiteType()59     WireFormat.FieldType getLiteType();
60 
getLiteJavaType()61     WireFormat.JavaType getLiteJavaType();
62 
isRepeated()63     boolean isRepeated();
64 
isPacked()65     boolean isPacked();
66 
getEnumType()67     Internal.EnumLiteMap<?> getEnumType();
68 
69     // If getLiteJavaType() == MESSAGE, this merges a message object of the
70     // type into a builder of the type.  Returns {@code to}.
internalMergeFrom(MessageLite.Builder to, MessageLite from)71     MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from);
72   }
73 
74   private static final int DEFAULT_FIELD_MAP_ARRAY_SIZE = 16;
75 
76   private final SmallSortedMap<T, Object> fields;
77   private boolean isImmutable;
78   private boolean hasLazyField;
79 
80   /** Construct a new FieldSet. */
FieldSet()81   private FieldSet() {
82     this.fields = SmallSortedMap.newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE);
83   }
84 
85   /** Construct an empty FieldSet. This is only used to initialize DEFAULT_INSTANCE. */
86   @SuppressWarnings("unused")
FieldSet(final boolean dummy)87   private FieldSet(final boolean dummy) {
88     this(SmallSortedMap.<T>newFieldMap(0));
89     makeImmutable();
90   }
91 
FieldSet(SmallSortedMap<T, Object> fields)92   private FieldSet(SmallSortedMap<T, Object> fields) {
93     this.fields = fields;
94     makeImmutable();
95   }
96 
97   /** Construct a new FieldSet. */
newFieldSet()98   public static <T extends FieldSet.FieldDescriptorLite<T>> FieldSet<T> newFieldSet() {
99     return new FieldSet<T>();
100   }
101 
102   /** Get an immutable empty FieldSet. */
103   @SuppressWarnings("unchecked")
emptySet()104   public static <T extends FieldSet.FieldDescriptorLite<T>> FieldSet<T> emptySet() {
105     return DEFAULT_INSTANCE;
106   }
107 
108   /** Construct a new Builder. */
newBuilder()109   public static <T extends FieldDescriptorLite<T>> Builder<T> newBuilder() {
110     return new Builder<T>();
111   }
112 
113   @SuppressWarnings("rawtypes")
114   private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
115 
116   /** Returns {@code true} if empty, {@code false} otherwise. */
isEmpty()117   boolean isEmpty() {
118     return fields.isEmpty();
119   }
120 
121   /** Make this FieldSet immutable from this point forward. */
122   @SuppressWarnings("unchecked")
makeImmutable()123   public void makeImmutable() {
124     if (isImmutable) {
125       return;
126     }
127     fields.makeImmutable();
128     isImmutable = true;
129   }
130 
131   /**
132    * Returns whether the FieldSet is immutable. This is true if it is the {@link #emptySet} or if
133    * {@link #makeImmutable} were called.
134    *
135    * @return whether the FieldSet is immutable.
136    */
isImmutable()137   public boolean isImmutable() {
138     return isImmutable;
139   }
140 
141   @Override
equals(Object o)142   public boolean equals(Object o) {
143     if (this == o) {
144       return true;
145     }
146 
147     if (!(o instanceof FieldSet)) {
148       return false;
149     }
150 
151     FieldSet<?> other = (FieldSet<?>) o;
152     return fields.equals(other.fields);
153   }
154 
155   @Override
hashCode()156   public int hashCode() {
157     return fields.hashCode();
158   }
159 
160   /**
161    * Clones the FieldSet. The returned FieldSet will be mutable even if the original FieldSet was
162    * immutable.
163    *
164    * @return the newly cloned FieldSet
165    */
166   @Override
clone()167   public FieldSet<T> clone() {
168     // We can't just call fields.clone because List objects in the map
169     // should not be shared.
170     FieldSet<T> clone = FieldSet.newFieldSet();
171     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
172       Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
173       clone.setField(entry.getKey(), entry.getValue());
174     }
175     for (Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
176       clone.setField(entry.getKey(), entry.getValue());
177     }
178     clone.hasLazyField = hasLazyField;
179     return clone;
180   }
181 
182 
183   // =================================================================
184 
185   /** See {@link Message.Builder#clear()}. */
clear()186   public void clear() {
187     fields.clear();
188     hasLazyField = false;
189   }
190 
191   /** Get a simple map containing all the fields. */
getAllFields()192   public Map<T, Object> getAllFields() {
193     if (hasLazyField) {
194       SmallSortedMap<T, Object> result = cloneAllFieldsMap(fields, /* copyList */ false);
195       if (fields.isImmutable()) {
196         result.makeImmutable();
197       }
198       return result;
199     }
200     return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
201   }
202 
cloneAllFieldsMap( SmallSortedMap<T, Object> fields, boolean copyList)203   private static <T extends FieldDescriptorLite<T>> SmallSortedMap<T, Object> cloneAllFieldsMap(
204       SmallSortedMap<T, Object> fields, boolean copyList) {
205     SmallSortedMap<T, Object> result = SmallSortedMap.newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE);
206     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
207       cloneFieldEntry(result, fields.getArrayEntryAt(i), copyList);
208     }
209     for (Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
210       cloneFieldEntry(result, entry, copyList);
211     }
212     return result;
213   }
214 
cloneFieldEntry( Map<T, Object> map, Map.Entry<T, Object> entry, boolean copyList)215   private static <T extends FieldDescriptorLite<T>> void cloneFieldEntry(
216       Map<T, Object> map, Map.Entry<T, Object> entry, boolean copyList) {
217     T key = entry.getKey();
218     Object value = entry.getValue();
219     if (value instanceof LazyField) {
220       map.put(key, ((LazyField) value).getValue());
221     } else if (copyList && value instanceof List) {
222       map.put(key, new ArrayList<>((List<?>) value));
223     } else {
224       map.put(key, value);
225     }
226   }
227 
228   /**
229    * Get an iterator to the field map. This iterator should not be leaked out of the protobuf
230    * library as it is not protected from mutation when fields is not immutable.
231    */
iterator()232   public Iterator<Map.Entry<T, Object>> iterator() {
233     if (hasLazyField) {
234       return new LazyIterator<T>(fields.entrySet().iterator());
235     }
236     return fields.entrySet().iterator();
237   }
238 
239   /**
240    * Get an iterator over the fields in the map in descending (i.e. reverse) order. This iterator
241    * should not be leaked out of the protobuf library as it is not protected from mutation when
242    * fields is not immutable.
243    */
descendingIterator()244   Iterator<Map.Entry<T, Object>> descendingIterator() {
245     if (hasLazyField) {
246       return new LazyIterator<T>(fields.descendingEntrySet().iterator());
247     }
248     return fields.descendingEntrySet().iterator();
249   }
250 
251   /** Useful for implementing {@link Message#hasField(Descriptors.FieldDescriptor)}. */
hasField(final T descriptor)252   public boolean hasField(final T descriptor) {
253     if (descriptor.isRepeated()) {
254       throw new IllegalArgumentException("hasField() can only be called on non-repeated fields.");
255     }
256 
257     return fields.get(descriptor) != null;
258   }
259 
260   /**
261    * Useful for implementing {@link Message#getField(Descriptors.FieldDescriptor)}. This method
262    * returns {@code null} if the field is not set; in this case it is up to the caller to fetch the
263    * field's default value.
264    */
getField(final T descriptor)265   public Object getField(final T descriptor) {
266     Object o = fields.get(descriptor);
267     if (o instanceof LazyField) {
268       return ((LazyField) o).getValue();
269     }
270     return o;
271   }
272 
273   /**
274    * Useful for implementing {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
275    */
276   @SuppressWarnings({"unchecked", "rawtypes"})
setField(final T descriptor, Object value)277   public void setField(final T descriptor, Object value) {
278     if (descriptor.isRepeated()) {
279       if (!(value instanceof List)) {
280         throw new IllegalArgumentException(
281             "Wrong object type used with protocol message reflection.");
282       }
283 
284       // Wrap the contents in a new list so that the caller cannot change
285       // the list's contents after setting it.
286       final List newList = new ArrayList();
287       newList.addAll((List) value);
288       for (final Object element : newList) {
289         verifyType(descriptor.getLiteType(), element);
290       }
291       value = newList;
292     } else {
293       verifyType(descriptor.getLiteType(), value);
294     }
295 
296     if (value instanceof LazyField) {
297       hasLazyField = true;
298     }
299     fields.put(descriptor, value);
300   }
301 
302   /** Useful for implementing {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
clearField(final T descriptor)303   public void clearField(final T descriptor) {
304     fields.remove(descriptor);
305     if (fields.isEmpty()) {
306       hasLazyField = false;
307     }
308   }
309 
310   /** Useful for implementing {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}. */
getRepeatedFieldCount(final T descriptor)311   public int getRepeatedFieldCount(final T descriptor) {
312     if (!descriptor.isRepeated()) {
313       throw new IllegalArgumentException(
314           "getRepeatedField() can only be called on repeated fields.");
315     }
316 
317     final Object value = getField(descriptor);
318     if (value == null) {
319       return 0;
320     } else {
321       return ((List<?>) value).size();
322     }
323   }
324 
325   /** Useful for implementing {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}. */
getRepeatedField(final T descriptor, final int index)326   public Object getRepeatedField(final T descriptor, final int index) {
327     if (!descriptor.isRepeated()) {
328       throw new IllegalArgumentException(
329           "getRepeatedField() can only be called on repeated fields.");
330     }
331 
332     final Object value = getField(descriptor);
333 
334     if (value == null) {
335       throw new IndexOutOfBoundsException();
336     } else {
337       return ((List<?>) value).get(index);
338     }
339   }
340 
341   /**
342    * Useful for implementing {@link
343    * Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
344    */
345   @SuppressWarnings("unchecked")
setRepeatedField(final T descriptor, final int index, final Object value)346   public void setRepeatedField(final T descriptor, final int index, final Object value) {
347     if (!descriptor.isRepeated()) {
348       throw new IllegalArgumentException(
349           "getRepeatedField() can only be called on repeated fields.");
350     }
351 
352     final Object list = getField(descriptor);
353     if (list == null) {
354       throw new IndexOutOfBoundsException();
355     }
356 
357     verifyType(descriptor.getLiteType(), value);
358     ((List<Object>) list).set(index, value);
359   }
360 
361   /**
362    * Useful for implementing {@link
363    * Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
364    */
365   @SuppressWarnings("unchecked")
addRepeatedField(final T descriptor, final Object value)366   public void addRepeatedField(final T descriptor, final Object value) {
367     if (!descriptor.isRepeated()) {
368       throw new IllegalArgumentException(
369           "addRepeatedField() can only be called on repeated fields.");
370     }
371 
372     verifyType(descriptor.getLiteType(), value);
373 
374     final Object existingValue = getField(descriptor);
375     List<Object> list;
376     if (existingValue == null) {
377       list = new ArrayList<Object>();
378       fields.put(descriptor, list);
379     } else {
380       list = (List<Object>) existingValue;
381     }
382 
383     list.add(value);
384   }
385 
386   /**
387    * Verifies that the given object is of the correct type to be a valid value for the given field.
388    * (For repeated fields, this checks if the object is the right type to be one element of the
389    * field.)
390    *
391    * @throws IllegalArgumentException The value is not of the right type.
392    */
verifyType(final WireFormat.FieldType type, final Object value)393   private void verifyType(final WireFormat.FieldType type, final Object value) {
394     if (!isValidType(type, value)) {
395       // TODO(kenton):  When chaining calls to setField(), it can be hard to
396       //   tell from the stack trace which exact call failed, since the whole
397       //   chain is considered one line of code.  It would be nice to print
398       //   more information here, e.g. naming the field.  We used to do that.
399       //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
400       //   isn't a big deal, though, since it would only really apply when using
401       //   reflection and generally people don't chain reflection setters.
402       throw new IllegalArgumentException(
403           "Wrong object type used with protocol message reflection.");
404     }
405   }
406 
isValidType(final WireFormat.FieldType type, final Object value)407   private static boolean isValidType(final WireFormat.FieldType type, final Object value) {
408     checkNotNull(value);
409     switch (type.getJavaType()) {
410       case INT:
411         return value instanceof Integer;
412       case LONG:
413         return value instanceof Long;
414       case FLOAT:
415         return value instanceof Float;
416       case DOUBLE:
417         return value instanceof Double;
418       case BOOLEAN:
419         return value instanceof Boolean;
420       case STRING:
421         return value instanceof String;
422       case BYTE_STRING:
423         return value instanceof ByteString || value instanceof byte[];
424       case ENUM:
425         // TODO(kenton):  Caller must do type checking here, I guess.
426         return (value instanceof Integer || value instanceof Internal.EnumLite);
427       case MESSAGE:
428         // TODO(kenton):  Caller must do type checking here, I guess.
429         return (value instanceof MessageLite) || (value instanceof LazyField);
430     }
431     return false;
432   }
433 
434   // =================================================================
435   // Parsing and serialization
436 
437   /**
438    * See {@link Message#isInitialized()}. Note: Since {@code FieldSet} itself does not have any way
439    * of knowing about required fields that aren't actually present in the set, it is up to the
440    * caller to check that all required fields are present.
441    */
isInitialized()442   public boolean isInitialized() {
443     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
444       if (!isInitialized(fields.getArrayEntryAt(i))) {
445         return false;
446       }
447     }
448     for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
449       if (!isInitialized(entry)) {
450         return false;
451       }
452     }
453     return true;
454   }
455 
456   @SuppressWarnings("unchecked")
isInitialized( final Map.Entry<T, Object> entry)457   private static <T extends FieldDescriptorLite<T>> boolean isInitialized(
458       final Map.Entry<T, Object> entry) {
459     final T descriptor = entry.getKey();
460     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
461       if (descriptor.isRepeated()) {
462         for (final MessageLite element : (List<MessageLite>) entry.getValue()) {
463           if (!element.isInitialized()) {
464             return false;
465           }
466         }
467       } else {
468         Object value = entry.getValue();
469         if (value instanceof MessageLite) {
470           if (!((MessageLite) value).isInitialized()) {
471             return false;
472           }
473         } else if (value instanceof LazyField) {
474           return true;
475         } else {
476           throw new IllegalArgumentException(
477               "Wrong object type used with protocol message reflection.");
478         }
479       }
480     }
481     return true;
482   }
483 
484   /**
485    * Given a field type, return the wire type.
486    *
487    * @return One of the {@code WIRETYPE_} constants defined in {@link WireFormat}.
488    */
getWireFormatForFieldType(final WireFormat.FieldType type, boolean isPacked)489   static int getWireFormatForFieldType(final WireFormat.FieldType type, boolean isPacked) {
490     if (isPacked) {
491       return WireFormat.WIRETYPE_LENGTH_DELIMITED;
492     } else {
493       return type.getWireType();
494     }
495   }
496 
497   /** Like {@link Message.Builder#mergeFrom(Message)}, but merges from another {@link FieldSet}. */
mergeFrom(final FieldSet<T> other)498   public void mergeFrom(final FieldSet<T> other) {
499     for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
500       mergeFromField(other.fields.getArrayEntryAt(i));
501     }
502     for (final Map.Entry<T, Object> entry : other.fields.getOverflowEntries()) {
503       mergeFromField(entry);
504     }
505   }
506 
cloneIfMutable(Object value)507   private static Object cloneIfMutable(Object value) {
508     if (value instanceof byte[]) {
509       byte[] bytes = (byte[]) value;
510       byte[] copy = new byte[bytes.length];
511       System.arraycopy(bytes, 0, copy, 0, bytes.length);
512       return copy;
513     } else {
514       return value;
515     }
516   }
517 
518   @SuppressWarnings({"unchecked", "rawtypes"})
mergeFromField(final Map.Entry<T, Object> entry)519   private void mergeFromField(final Map.Entry<T, Object> entry) {
520     final T descriptor = entry.getKey();
521     Object otherValue = entry.getValue();
522     if (otherValue instanceof LazyField) {
523       otherValue = ((LazyField) otherValue).getValue();
524     }
525 
526     if (descriptor.isRepeated()) {
527       Object value = getField(descriptor);
528       if (value == null) {
529         value = new ArrayList<>();
530       }
531       for (Object element : (List) otherValue) {
532         ((List) value).add(cloneIfMutable(element));
533       }
534       fields.put(descriptor, value);
535     } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
536       Object value = getField(descriptor);
537       if (value == null) {
538         fields.put(descriptor, cloneIfMutable(otherValue));
539       } else {
540         // Merge the messages.
541           value =
542               descriptor
543                   .internalMergeFrom(((MessageLite) value).toBuilder(), (MessageLite) otherValue)
544                   .build();
545         fields.put(descriptor, value);
546       }
547     } else {
548       fields.put(descriptor, cloneIfMutable(otherValue));
549     }
550   }
551 
552   // TODO(kenton):  Move static parsing and serialization methods into some
553   //   other class.  Probably WireFormat.
554 
555   /**
556    * Read a field of any primitive type for immutable messages from a CodedInputStream. Enums,
557    * groups, and embedded messages are not handled by this method.
558    *
559    * @param input The stream from which to read.
560    * @param type Declared type of the field.
561    * @param checkUtf8 When true, check that the input is valid utf8.
562    * @return An object representing the field's value, of the exact type which would be returned by
563    *     {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
564    */
readPrimitiveField( CodedInputStream input, final WireFormat.FieldType type, boolean checkUtf8)565   public static Object readPrimitiveField(
566       CodedInputStream input, final WireFormat.FieldType type, boolean checkUtf8)
567       throws IOException {
568     if (checkUtf8) {
569       return WireFormat.readPrimitiveField(input, type, WireFormat.Utf8Validation.STRICT);
570     } else {
571       return WireFormat.readPrimitiveField(input, type, WireFormat.Utf8Validation.LOOSE);
572     }
573   }
574 
575 
576   /** See {@link Message#writeTo(CodedOutputStream)}. */
writeTo(final CodedOutputStream output)577   public void writeTo(final CodedOutputStream output) throws IOException {
578     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
579       final Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
580       writeField(entry.getKey(), entry.getValue(), output);
581     }
582     for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
583       writeField(entry.getKey(), entry.getValue(), output);
584     }
585   }
586 
587   /** Like {@link #writeTo} but uses MessageSet wire format. */
writeMessageSetTo(final CodedOutputStream output)588   public void writeMessageSetTo(final CodedOutputStream output) throws IOException {
589     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
590       writeMessageSetTo(fields.getArrayEntryAt(i), output);
591     }
592     for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
593       writeMessageSetTo(entry, output);
594     }
595   }
596 
writeMessageSetTo(final Map.Entry<T, Object> entry, final CodedOutputStream output)597   private void writeMessageSetTo(final Map.Entry<T, Object> entry, final CodedOutputStream output)
598       throws IOException {
599     final T descriptor = entry.getKey();
600     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
601         && !descriptor.isRepeated()
602         && !descriptor.isPacked()) {
603       Object value = entry.getValue();
604       if (value instanceof LazyField) {
605         value = ((LazyField) value).getValue();
606       }
607       output.writeMessageSetExtension(entry.getKey().getNumber(), (MessageLite) value);
608     } else {
609       writeField(descriptor, entry.getValue(), output);
610     }
611   }
612 
613   /**
614    * Write a single tag-value pair to the stream.
615    *
616    * @param output The output stream.
617    * @param type The field's type.
618    * @param number The field's number.
619    * @param value Object representing the field's value. Must be of the exact type which would be
620    *     returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
621    */
writeElement( final CodedOutputStream output, final WireFormat.FieldType type, final int number, final Object value)622   static void writeElement(
623       final CodedOutputStream output,
624       final WireFormat.FieldType type,
625       final int number,
626       final Object value)
627       throws IOException {
628     // Special case for groups, which need a start and end tag; other fields
629     // can just use writeTag() and writeFieldNoTag().
630     if (type == WireFormat.FieldType.GROUP) {
631         output.writeGroup(number, (MessageLite) value);
632     } else {
633       output.writeTag(number, getWireFormatForFieldType(type, false));
634       writeElementNoTag(output, type, value);
635     }
636   }
637 
638   /**
639    * Write a field of arbitrary type, without its tag, to the stream.
640    *
641    * @param output The output stream.
642    * @param type The field's type.
643    * @param value Object representing the field's value. Must be of the exact type which would be
644    *     returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
645    */
writeElementNoTag( final CodedOutputStream output, final WireFormat.FieldType type, final Object value)646   static void writeElementNoTag(
647       final CodedOutputStream output, final WireFormat.FieldType type, final Object value)
648       throws IOException {
649     switch (type) {
650       case DOUBLE:
651         output.writeDoubleNoTag((Double) value);
652         break;
653       case FLOAT:
654         output.writeFloatNoTag((Float) value);
655         break;
656       case INT64:
657         output.writeInt64NoTag((Long) value);
658         break;
659       case UINT64:
660         output.writeUInt64NoTag((Long) value);
661         break;
662       case INT32:
663         output.writeInt32NoTag((Integer) value);
664         break;
665       case FIXED64:
666         output.writeFixed64NoTag((Long) value);
667         break;
668       case FIXED32:
669         output.writeFixed32NoTag((Integer) value);
670         break;
671       case BOOL:
672         output.writeBoolNoTag((Boolean) value);
673         break;
674       case GROUP:
675         output.writeGroupNoTag((MessageLite) value);
676         break;
677       case MESSAGE:
678         output.writeMessageNoTag((MessageLite) value);
679         break;
680       case STRING:
681         if (value instanceof ByteString) {
682           output.writeBytesNoTag((ByteString) value);
683         } else {
684           output.writeStringNoTag((String) value);
685         }
686         break;
687       case BYTES:
688         if (value instanceof ByteString) {
689           output.writeBytesNoTag((ByteString) value);
690         } else {
691           output.writeByteArrayNoTag((byte[]) value);
692         }
693         break;
694       case UINT32:
695         output.writeUInt32NoTag((Integer) value);
696         break;
697       case SFIXED32:
698         output.writeSFixed32NoTag((Integer) value);
699         break;
700       case SFIXED64:
701         output.writeSFixed64NoTag((Long) value);
702         break;
703       case SINT32:
704         output.writeSInt32NoTag((Integer) value);
705         break;
706       case SINT64:
707         output.writeSInt64NoTag((Long) value);
708         break;
709 
710       case ENUM:
711         if (value instanceof Internal.EnumLite) {
712           output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
713         } else {
714           output.writeEnumNoTag(((Integer) value).intValue());
715         }
716         break;
717     }
718   }
719 
720   /** Write a single field. */
writeField( final FieldDescriptorLite<?> descriptor, final Object value, final CodedOutputStream output)721   public static void writeField(
722       final FieldDescriptorLite<?> descriptor, final Object value, final CodedOutputStream output)
723       throws IOException {
724     WireFormat.FieldType type = descriptor.getLiteType();
725     int number = descriptor.getNumber();
726     if (descriptor.isRepeated()) {
727       final List<?> valueList = (List<?>) value;
728       if (descriptor.isPacked()) {
729         output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
730         // Compute the total data size so the length can be written.
731         int dataSize = 0;
732         for (final Object element : valueList) {
733           dataSize += computeElementSizeNoTag(type, element);
734         }
735         output.writeRawVarint32(dataSize);
736         // Write the data itself, without any tags.
737         for (final Object element : valueList) {
738           writeElementNoTag(output, type, element);
739         }
740       } else {
741         for (final Object element : valueList) {
742           writeElement(output, type, number, element);
743         }
744       }
745     } else {
746       if (value instanceof LazyField) {
747         writeElement(output, type, number, ((LazyField) value).getValue());
748       } else {
749         writeElement(output, type, number, value);
750       }
751     }
752   }
753 
754   /**
755    * See {@link Message#getSerializedSize()}. It's up to the caller to cache the resulting size if
756    * desired.
757    */
getSerializedSize()758   public int getSerializedSize() {
759     int size = 0;
760     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
761       final Map.Entry<T, Object> entry = fields.getArrayEntryAt(i);
762       size += computeFieldSize(entry.getKey(), entry.getValue());
763     }
764     for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
765       size += computeFieldSize(entry.getKey(), entry.getValue());
766     }
767     return size;
768   }
769 
770   /** Like {@link #getSerializedSize} but uses MessageSet wire format. */
getMessageSetSerializedSize()771   public int getMessageSetSerializedSize() {
772     int size = 0;
773     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
774       size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
775     }
776     for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
777       size += getMessageSetSerializedSize(entry);
778     }
779     return size;
780   }
781 
getMessageSetSerializedSize(final Map.Entry<T, Object> entry)782   private int getMessageSetSerializedSize(final Map.Entry<T, Object> entry) {
783     final T descriptor = entry.getKey();
784     Object value = entry.getValue();
785     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
786         && !descriptor.isRepeated()
787         && !descriptor.isPacked()) {
788       if (value instanceof LazyField) {
789         return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
790             entry.getKey().getNumber(), (LazyField) value);
791       } else {
792         return CodedOutputStream.computeMessageSetExtensionSize(
793             entry.getKey().getNumber(), (MessageLite) value);
794       }
795     } else {
796       return computeFieldSize(descriptor, value);
797     }
798   }
799 
800   /**
801    * Compute the number of bytes that would be needed to encode a single tag/value pair of arbitrary
802    * type.
803    *
804    * @param type The field's type.
805    * @param number The field's number.
806    * @param value Object representing the field's value. Must be of the exact type which would be
807    *     returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
808    */
computeElementSize( final WireFormat.FieldType type, final int number, final Object value)809   static int computeElementSize(
810       final WireFormat.FieldType type, final int number, final Object value) {
811     int tagSize = CodedOutputStream.computeTagSize(number);
812     if (type == WireFormat.FieldType.GROUP) {
813       // Only count the end group tag for proto2 messages as for proto1 the end
814       // group tag will be counted as a part of getSerializedSize().
815         tagSize *= 2;
816     }
817     return tagSize + computeElementSizeNoTag(type, value);
818   }
819 
820   /**
821    * Compute the number of bytes that would be needed to encode a particular value of arbitrary
822    * type, excluding tag.
823    *
824    * @param type The field's type.
825    * @param value Object representing the field's value. Must be of the exact type which would be
826    *     returned by {@link Message#getField(Descriptors.FieldDescriptor)} for this field.
827    */
computeElementSizeNoTag(final WireFormat.FieldType type, final Object value)828   static int computeElementSizeNoTag(final WireFormat.FieldType type, final Object value) {
829     switch (type) {
830         // Note:  Minor violation of 80-char limit rule here because this would
831         //   actually be harder to read if we wrapped the lines.
832       case DOUBLE:
833         return CodedOutputStream.computeDoubleSizeNoTag((Double) value);
834       case FLOAT:
835         return CodedOutputStream.computeFloatSizeNoTag((Float) value);
836       case INT64:
837         return CodedOutputStream.computeInt64SizeNoTag((Long) value);
838       case UINT64:
839         return CodedOutputStream.computeUInt64SizeNoTag((Long) value);
840       case INT32:
841         return CodedOutputStream.computeInt32SizeNoTag((Integer) value);
842       case FIXED64:
843         return CodedOutputStream.computeFixed64SizeNoTag((Long) value);
844       case FIXED32:
845         return CodedOutputStream.computeFixed32SizeNoTag((Integer) value);
846       case BOOL:
847         return CodedOutputStream.computeBoolSizeNoTag((Boolean) value);
848       case GROUP:
849         return CodedOutputStream.computeGroupSizeNoTag((MessageLite) value);
850       case BYTES:
851         if (value instanceof ByteString) {
852           return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
853         } else {
854           return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value);
855         }
856       case STRING:
857         if (value instanceof ByteString) {
858           return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
859         } else {
860           return CodedOutputStream.computeStringSizeNoTag((String) value);
861         }
862       case UINT32:
863         return CodedOutputStream.computeUInt32SizeNoTag((Integer) value);
864       case SFIXED32:
865         return CodedOutputStream.computeSFixed32SizeNoTag((Integer) value);
866       case SFIXED64:
867         return CodedOutputStream.computeSFixed64SizeNoTag((Long) value);
868       case SINT32:
869         return CodedOutputStream.computeSInt32SizeNoTag((Integer) value);
870       case SINT64:
871         return CodedOutputStream.computeSInt64SizeNoTag((Long) value);
872 
873       case MESSAGE:
874         if (value instanceof LazyField) {
875           return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
876         } else {
877           return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
878         }
879 
880       case ENUM:
881         if (value instanceof Internal.EnumLite) {
882           return CodedOutputStream.computeEnumSizeNoTag(((Internal.EnumLite) value).getNumber());
883         } else {
884           return CodedOutputStream.computeEnumSizeNoTag((Integer) value);
885         }
886     }
887 
888     throw new RuntimeException("There is no way to get here, but the compiler thinks otherwise.");
889   }
890 
891   /** Compute the number of bytes needed to encode a particular field. */
computeFieldSize(final FieldDescriptorLite<?> descriptor, final Object value)892   public static int computeFieldSize(final FieldDescriptorLite<?> descriptor, final Object value) {
893     WireFormat.FieldType type = descriptor.getLiteType();
894     int number = descriptor.getNumber();
895     if (descriptor.isRepeated()) {
896       if (descriptor.isPacked()) {
897         int dataSize = 0;
898         for (final Object element : (List<?>) value) {
899           dataSize += computeElementSizeNoTag(type, element);
900         }
901         return dataSize
902             + CodedOutputStream.computeTagSize(number)
903             + CodedOutputStream.computeRawVarint32Size(dataSize);
904       } else {
905         int size = 0;
906         for (final Object element : (List<?>) value) {
907           size += computeElementSize(type, number, element);
908         }
909         return size;
910       }
911     } else {
912       return computeElementSize(type, number, value);
913     }
914   }
915 
916   /**
917    * A FieldSet Builder that accept a {@link MessageLite.Builder} as a field value. This is useful
918    * for implementing methods in {@link MessageLite.Builder}.
919    */
920   static final class Builder<T extends FieldDescriptorLite<T>> {
921 
922     private SmallSortedMap<T, Object> fields;
923     private boolean hasLazyField;
924     private boolean isMutable;
925     private boolean hasNestedBuilders;
926 
Builder()927     private Builder() {
928       this(SmallSortedMap.<T>newFieldMap(DEFAULT_FIELD_MAP_ARRAY_SIZE));
929     }
930 
Builder(SmallSortedMap<T, Object> fields)931     private Builder(SmallSortedMap<T, Object> fields) {
932       this.fields = fields;
933       this.isMutable = true;
934     }
935 
936     /** Creates the FieldSet */
build()937     public FieldSet<T> build() {
938       if (fields.isEmpty()) {
939         return FieldSet.emptySet();
940       }
941       isMutable = false;
942       SmallSortedMap<T, Object> fieldsForBuild = fields;
943       if (hasNestedBuilders) {
944         // Make a copy of the fields map with all Builders replaced by Message.
945         fieldsForBuild = cloneAllFieldsMap(fields, /* copyList */ false);
946         replaceBuilders(fieldsForBuild);
947       }
948       FieldSet<T> fieldSet = new FieldSet<>(fieldsForBuild);
949       fieldSet.hasLazyField = hasLazyField;
950       return fieldSet;
951     }
952 
replaceBuilders( SmallSortedMap<T, Object> fieldMap)953     private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
954         SmallSortedMap<T, Object> fieldMap) {
955       for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
956         replaceBuilders(fieldMap.getArrayEntryAt(i));
957       }
958       for (Map.Entry<T, Object> entry : fieldMap.getOverflowEntries()) {
959         replaceBuilders(entry);
960       }
961     }
962 
replaceBuilders( Map.Entry<T, Object> entry)963     private static <T extends FieldDescriptorLite<T>> void replaceBuilders(
964         Map.Entry<T, Object> entry) {
965       entry.setValue(replaceBuilders(entry.getKey(), entry.getValue()));
966     }
967 
replaceBuilders( T descriptor, Object value)968     private static <T extends FieldDescriptorLite<T>> Object replaceBuilders(
969         T descriptor, Object value) {
970       if (value == null) {
971         return value;
972       }
973       if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
974         if (descriptor.isRepeated()) {
975           if (!(value instanceof List)) {
976             throw new IllegalStateException(
977                 "Repeated field should contains a List but actually contains type: "
978                     + value.getClass());
979           }
980           @SuppressWarnings("unchecked")  // We just check that value is an instance of List above.
981           List<Object> list = (List<Object>) value;
982           for (int i = 0; i < list.size(); i++) {
983             Object oldElement = list.get(i);
984             Object newElement = replaceBuilder(oldElement);
985             if (newElement != oldElement) {
986               // If the list contains a Message.Builder, then make a copy of that list and then
987               // modify the Message.Builder into a Message and return the new list. This way, the
988               // existing Message.Builder will still be able to modify the inner fields of the
989               // original FieldSet.Builder.
990               if (list == value) {
991                 list = new ArrayList<>(list);
992               }
993               list.set(i, newElement);
994             }
995           }
996           return list;
997         } else {
998           return replaceBuilder(value);
999         }
1000       }
1001       return value;
1002     }
1003 
replaceBuilder(Object value)1004     private static Object replaceBuilder(Object value) {
1005       return (value instanceof MessageLite.Builder) ? ((MessageLite.Builder) value).build() : value;
1006     }
1007 
1008     /** Returns a new Builder using the fields from {@code fieldSet}. */
fromFieldSet(FieldSet<T> fieldSet)1009     public static <T extends FieldDescriptorLite<T>> Builder<T> fromFieldSet(FieldSet<T> fieldSet) {
1010       Builder<T> builder = new Builder<T>(cloneAllFieldsMap(fieldSet.fields, /* copyList */ true));
1011       builder.hasLazyField = fieldSet.hasLazyField;
1012       return builder;
1013     }
1014 
1015     // =================================================================
1016 
1017     /** Get a simple map containing all the fields. */
getAllFields()1018     public Map<T, Object> getAllFields() {
1019       if (hasLazyField) {
1020         SmallSortedMap<T, Object> result = cloneAllFieldsMap(fields, /* copyList */ false);
1021         if (fields.isImmutable()) {
1022           result.makeImmutable();
1023         } else {
1024           replaceBuilders(result);
1025         }
1026         return result;
1027       }
1028       return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
1029     }
1030 
1031     /** Useful for implementing {@link Message#hasField(Descriptors.FieldDescriptor)}. */
hasField(final T descriptor)1032     public boolean hasField(final T descriptor) {
1033       if (descriptor.isRepeated()) {
1034         throw new IllegalArgumentException("hasField() can only be called on non-repeated fields.");
1035       }
1036 
1037       return fields.get(descriptor) != null;
1038     }
1039 
1040     /**
1041      * Useful for implementing {@link Message#getField(Descriptors.FieldDescriptor)}. This method
1042      * returns {@code null} if the field is not set; in this case it is up to the caller to fetch
1043      * the field's default value.
1044      */
getField(final T descriptor)1045     public Object getField(final T descriptor) {
1046       Object value = getFieldAllowBuilders(descriptor);
1047       return replaceBuilders(descriptor, value);
1048     }
1049 
1050     /** Same as {@link #getField(F)}, but allow a {@link MessageLite.Builder} to be returned. */
getFieldAllowBuilders(final T descriptor)1051     Object getFieldAllowBuilders(final T descriptor) {
1052       Object o = fields.get(descriptor);
1053       if (o instanceof LazyField) {
1054         return ((LazyField) o).getValue();
1055       }
1056       return o;
1057     }
1058 
ensureIsMutable()1059     private void ensureIsMutable() {
1060       if (!isMutable) {
1061         fields = cloneAllFieldsMap(fields, /* copyList */ true);
1062         isMutable = true;
1063       }
1064     }
1065 
1066     /**
1067      * Useful for implementing {@link Message.Builder#setField(Descriptors.FieldDescriptor,
1068      * Object)}.
1069      */
1070     @SuppressWarnings({"unchecked", "rawtypes"})
setField(final T descriptor, Object value)1071     public void setField(final T descriptor, Object value) {
1072       ensureIsMutable();
1073       if (descriptor.isRepeated()) {
1074         if (!(value instanceof List)) {
1075           throw new IllegalArgumentException(
1076               "Wrong object type used with protocol message reflection.");
1077         }
1078 
1079         // Wrap the contents in a new list so that the caller cannot change
1080         // the list's contents after setting it.
1081         final List newList = new ArrayList();
1082         newList.addAll((List) value);
1083         for (final Object element : newList) {
1084           verifyType(descriptor.getLiteType(), element);
1085           hasNestedBuilders = hasNestedBuilders || element instanceof MessageLite.Builder;
1086         }
1087         value = newList;
1088       } else {
1089         verifyType(descriptor.getLiteType(), value);
1090       }
1091 
1092       if (value instanceof LazyField) {
1093         hasLazyField = true;
1094       }
1095       hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
1096 
1097       fields.put(descriptor, value);
1098     }
1099 
1100     /** Useful for implementing {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
clearField(final T descriptor)1101     public void clearField(final T descriptor) {
1102       ensureIsMutable();
1103       fields.remove(descriptor);
1104       if (fields.isEmpty()) {
1105         hasLazyField = false;
1106       }
1107     }
1108 
1109     /**
1110      * Useful for implementing {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
1111      */
getRepeatedFieldCount(final T descriptor)1112     public int getRepeatedFieldCount(final T descriptor) {
1113       if (!descriptor.isRepeated()) {
1114         throw new IllegalArgumentException(
1115             "getRepeatedField() can only be called on repeated fields.");
1116       }
1117 
1118       final Object value = getField(descriptor);
1119       if (value == null) {
1120         return 0;
1121       } else {
1122         return ((List<?>) value).size();
1123       }
1124     }
1125 
1126     /**
1127      * Useful for implementing {@link Message#getRepeatedField(Descriptors.FieldDescriptor, int)}.
1128      */
getRepeatedField(final T descriptor, final int index)1129     public Object getRepeatedField(final T descriptor, final int index) {
1130       if (hasNestedBuilders) {
1131         ensureIsMutable();
1132       }
1133       Object value = getRepeatedFieldAllowBuilders(descriptor, index);
1134       return replaceBuilder(value);
1135     }
1136 
1137     /**
1138      * Same as {@link #getRepeatedField(F, int)}, but allow a {@link MessageLite.Builder} to be
1139      * returned.
1140      */
getRepeatedFieldAllowBuilders(final T descriptor, final int index)1141     Object getRepeatedFieldAllowBuilders(final T descriptor, final int index) {
1142       if (!descriptor.isRepeated()) {
1143         throw new IllegalArgumentException(
1144             "getRepeatedField() can only be called on repeated fields.");
1145       }
1146 
1147       final Object value = getFieldAllowBuilders(descriptor);
1148 
1149       if (value == null) {
1150         throw new IndexOutOfBoundsException();
1151       } else {
1152         return ((List<?>) value).get(index);
1153       }
1154     }
1155 
1156     /**
1157      * Useful for implementing {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,
1158      * int, Object)}.
1159      */
1160     @SuppressWarnings("unchecked")
setRepeatedField(final T descriptor, final int index, final Object value)1161     public void setRepeatedField(final T descriptor, final int index, final Object value) {
1162       ensureIsMutable();
1163       if (!descriptor.isRepeated()) {
1164         throw new IllegalArgumentException(
1165             "getRepeatedField() can only be called on repeated fields.");
1166       }
1167 
1168       hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
1169 
1170       final Object list = getField(descriptor);
1171       if (list == null) {
1172         throw new IndexOutOfBoundsException();
1173       }
1174 
1175       verifyType(descriptor.getLiteType(), value);
1176       ((List<Object>) list).set(index, value);
1177     }
1178 
1179     /**
1180      * Useful for implementing {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,
1181      * Object)}.
1182      */
1183     @SuppressWarnings("unchecked")
addRepeatedField(final T descriptor, final Object value)1184     public void addRepeatedField(final T descriptor, final Object value) {
1185       ensureIsMutable();
1186       if (!descriptor.isRepeated()) {
1187         throw new IllegalArgumentException(
1188             "addRepeatedField() can only be called on repeated fields.");
1189       }
1190 
1191       hasNestedBuilders = hasNestedBuilders || value instanceof MessageLite.Builder;
1192 
1193       verifyType(descriptor.getLiteType(), value);
1194 
1195       final Object existingValue = getField(descriptor);
1196       List<Object> list;
1197       if (existingValue == null) {
1198         list = new ArrayList<>();
1199         fields.put(descriptor, list);
1200       } else {
1201         list = (List<Object>) existingValue;
1202       }
1203 
1204       list.add(value);
1205     }
1206 
1207     /**
1208      * Verifies that the given object is of the correct type to be a valid value for the given
1209      * field. (For repeated fields, this checks if the object is the right type to be one element of
1210      * the field.)
1211      *
1212      * @throws IllegalArgumentException The value is not of the right type.
1213      */
verifyType(final WireFormat.FieldType type, final Object value)1214     private static void verifyType(final WireFormat.FieldType type, final Object value) {
1215       if (!FieldSet.isValidType(type, value)) {
1216         // Builder can accept Message.Builder values even though FieldSet will reject.
1217         if (type.getJavaType() == WireFormat.JavaType.MESSAGE
1218             && value instanceof MessageLite.Builder) {
1219           return;
1220         }
1221         throw new IllegalArgumentException(
1222             "Wrong object type used with protocol message reflection.");
1223       }
1224     }
1225 
1226     /**
1227      * See {@link Message#isInitialized()}. Note: Since {@code FieldSet} itself does not have any
1228      * way of knowing about required fields that aren't actually present in the set, it is up to the
1229      * caller to check that all required fields are present.
1230      */
isInitialized()1231     public boolean isInitialized() {
1232       for (int i = 0; i < fields.getNumArrayEntries(); i++) {
1233         if (!FieldSet.isInitialized(fields.getArrayEntryAt(i))) {
1234           return false;
1235         }
1236       }
1237       for (final Map.Entry<T, Object> entry : fields.getOverflowEntries()) {
1238         if (!FieldSet.isInitialized(entry)) {
1239           return false;
1240         }
1241       }
1242       return true;
1243     }
1244 
1245     /**
1246      * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another {@link FieldSet}.
1247      */
mergeFrom(final FieldSet<T> other)1248     public void mergeFrom(final FieldSet<T> other) {
1249       ensureIsMutable();
1250       for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
1251         mergeFromField(other.fields.getArrayEntryAt(i));
1252       }
1253       for (final Map.Entry<T, Object> entry : other.fields.getOverflowEntries()) {
1254         mergeFromField(entry);
1255       }
1256     }
1257 
1258     @SuppressWarnings({"unchecked", "rawtypes"})
mergeFromField(final Map.Entry<T, Object> entry)1259     private void mergeFromField(final Map.Entry<T, Object> entry) {
1260       final T descriptor = entry.getKey();
1261       Object otherValue = entry.getValue();
1262       if (otherValue instanceof LazyField) {
1263         otherValue = ((LazyField) otherValue).getValue();
1264       }
1265 
1266       if (descriptor.isRepeated()) {
1267         Object value = getField(descriptor);
1268         if (value == null) {
1269           value = new ArrayList<>();
1270         }
1271         for (Object element : (List) otherValue) {
1272           ((List) value).add(FieldSet.cloneIfMutable(element));
1273         }
1274         fields.put(descriptor, value);
1275       } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
1276         Object value = getField(descriptor);
1277         if (value == null) {
1278           fields.put(descriptor, FieldSet.cloneIfMutable(otherValue));
1279         } else {
1280           // Merge the messages.
1281           if (value instanceof MessageLite.Builder) {
1282             descriptor.internalMergeFrom((MessageLite.Builder) value, (MessageLite) otherValue);
1283           } else {
1284             value =
1285                 descriptor
1286                     .internalMergeFrom(((MessageLite) value).toBuilder(), (MessageLite) otherValue)
1287                     .build();
1288             fields.put(descriptor, value);
1289           }
1290         }
1291       } else {
1292         fields.put(descriptor, cloneIfMutable(otherValue));
1293       }
1294     }
1295   }
1296 }
1297