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