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