1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // http://code.google.com/p/protobuf/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
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
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.
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.
31 package com.google.protobuf;
33 import com.google.protobuf.LazyField.LazyIterator;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.Iterator;
39 import java.util.List;
43 * A class which represents an arbitrary set of fields of some message type.
44 * This is used to implement {@link DynamicMessage}, and also to represent
45 * extensions in {@link GeneratedMessage}. This class is package-private,
46 * since outside users should probably be using {@link DynamicMessage}.
48 * @author kenton@google.com Kenton Varda
50 final class FieldSet<FieldDescriptorType extends
51 FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
53 * Interface for a FieldDescriptor or lite extension descriptor. This
54 * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
56 public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
57 extends Comparable<T> {
59 WireFormat.FieldType getLiteType();
60 WireFormat.JavaType getLiteJavaType();
63 Internal.EnumLiteMap<?> getEnumType();
65 // If getLiteJavaType() == MESSAGE, this merges a message object of the
66 // type into a builder of the type. Returns {@code to}.
67 MessageLite.Builder internalMergeFrom(
68 MessageLite.Builder to, MessageLite from);
71 private final SmallSortedMap<FieldDescriptorType, Object> fields;
72 private boolean isImmutable;
73 private boolean hasLazyField = false;
75 /** Construct a new FieldSet. */
77 this.fields = SmallSortedMap.newFieldMap(16);
81 * Construct an empty FieldSet. This is only used to initialize
84 private FieldSet(final boolean dummy) {
85 this.fields = SmallSortedMap.newFieldMap(0);
89 /** Construct a new FieldSet. */
90 public static <T extends FieldSet.FieldDescriptorLite<T>>
91 FieldSet<T> newFieldSet() {
92 return new FieldSet<T>();
95 /** Get an immutable empty FieldSet. */
96 @SuppressWarnings("unchecked")
97 public static <T extends FieldSet.FieldDescriptorLite<T>>
98 FieldSet<T> emptySet() {
99 return DEFAULT_INSTANCE;
101 @SuppressWarnings("rawtypes")
102 private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
104 /** Make this FieldSet immutable from this point forward. */
105 @SuppressWarnings("unchecked")
106 public void makeImmutable() {
110 fields.makeImmutable();
115 * Returns whether the FieldSet is immutable. This is true if it is the
116 * {@link #emptySet} or if {@link #makeImmutable} were called.
118 * @return whether the FieldSet is immutable.
120 public boolean isImmutable() {
125 * Clones the FieldSet. The returned FieldSet will be mutable even if the
126 * original FieldSet was immutable.
128 * @return the newly cloned FieldSet
131 public FieldSet<FieldDescriptorType> clone() {
132 // We can't just call fields.clone because List objects in the map
133 // should not be shared.
134 FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
135 for (int i = 0; i < fields.getNumArrayEntries(); i++) {
136 Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
137 FieldDescriptorType descriptor = entry.getKey();
138 clone.setField(descriptor, entry.getValue());
140 for (Map.Entry<FieldDescriptorType, Object> entry :
141 fields.getOverflowEntries()) {
142 FieldDescriptorType descriptor = entry.getKey();
143 clone.setField(descriptor, entry.getValue());
145 clone.hasLazyField = hasLazyField;
149 // =================================================================
151 /** See {@link Message.Builder#clear()}. */
152 public void clear() {
154 hasLazyField = false;
158 * Get a simple map containing all the fields.
160 public Map<FieldDescriptorType, Object> getAllFields() {
162 SmallSortedMap<FieldDescriptorType, Object> result =
163 SmallSortedMap.newFieldMap(16);
164 for (int i = 0; i < fields.getNumArrayEntries(); i++) {
165 cloneFieldEntry(result, fields.getArrayEntryAt(i));
167 for (Map.Entry<FieldDescriptorType, Object> entry :
168 fields.getOverflowEntries()) {
169 cloneFieldEntry(result, entry);
171 if (fields.isImmutable()) {
172 result.makeImmutable();
176 return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
179 private void cloneFieldEntry(Map<FieldDescriptorType, Object> map,
180 Map.Entry<FieldDescriptorType, Object> entry) {
181 FieldDescriptorType key = entry.getKey();
182 Object value = entry.getValue();
183 if (value instanceof LazyField) {
184 map.put(key, ((LazyField) value).getValue());
191 * Get an iterator to the field map. This iterator should not be leaked out
192 * of the protobuf library as it is not protected from mutation when fields
195 public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
197 return new LazyIterator<FieldDescriptorType>(
198 fields.entrySet().iterator());
200 return fields.entrySet().iterator();
204 * Useful for implementing
205 * {@link Message#hasField(Descriptors.FieldDescriptor)}.
207 public boolean hasField(final FieldDescriptorType descriptor) {
208 if (descriptor.isRepeated()) {
209 throw new IllegalArgumentException(
210 "hasField() can only be called on non-repeated fields.");
213 return fields.get(descriptor) != null;
217 * Useful for implementing
218 * {@link Message#getField(Descriptors.FieldDescriptor)}. This method
219 * returns {@code null} if the field is not set; in this case it is up
220 * to the caller to fetch the field's default value.
222 public Object getField(final FieldDescriptorType descriptor) {
223 Object o = fields.get(descriptor);
224 if (o instanceof LazyField) {
225 return ((LazyField) o).getValue();
231 * Useful for implementing
232 * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
234 @SuppressWarnings({"unchecked", "rawtypes"})
235 public void setField(final FieldDescriptorType descriptor,
237 if (descriptor.isRepeated()) {
238 if (!(value instanceof List)) {
239 throw new IllegalArgumentException(
240 "Wrong object type used with protocol message reflection.");
243 // Wrap the contents in a new list so that the caller cannot change
244 // the list's contents after setting it.
245 final List newList = new ArrayList();
246 newList.addAll((List) value);
247 for (final Object element : newList) {
248 verifyType(descriptor.getLiteType(), element);
252 verifyType(descriptor.getLiteType(), value);
255 if (value instanceof LazyField) {
258 fields.put(descriptor, value);
262 * Useful for implementing
263 * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
265 public void clearField(final FieldDescriptorType descriptor) {
266 fields.remove(descriptor);
267 if (fields.isEmpty()) {
268 hasLazyField = false;
273 * Useful for implementing
274 * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
276 public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
277 if (!descriptor.isRepeated()) {
278 throw new IllegalArgumentException(
279 "getRepeatedField() can only be called on repeated fields.");
282 final Object value = getField(descriptor);
286 return ((List<?>) value).size();
291 * Useful for implementing
292 * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
294 public Object getRepeatedField(final FieldDescriptorType descriptor,
296 if (!descriptor.isRepeated()) {
297 throw new IllegalArgumentException(
298 "getRepeatedField() can only be called on repeated fields.");
301 final Object value = getField(descriptor);
304 throw new IndexOutOfBoundsException();
306 return ((List<?>) value).get(index);
311 * Useful for implementing
312 * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
314 @SuppressWarnings("unchecked")
315 public void setRepeatedField(final FieldDescriptorType descriptor,
317 final Object value) {
318 if (!descriptor.isRepeated()) {
319 throw new IllegalArgumentException(
320 "getRepeatedField() can only be called on repeated fields.");
323 final Object list = getField(descriptor);
325 throw new IndexOutOfBoundsException();
328 verifyType(descriptor.getLiteType(), value);
329 ((List<Object>) list).set(index, value);
333 * Useful for implementing
334 * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
336 @SuppressWarnings("unchecked")
337 public void addRepeatedField(final FieldDescriptorType descriptor,
338 final Object value) {
339 if (!descriptor.isRepeated()) {
340 throw new IllegalArgumentException(
341 "addRepeatedField() can only be called on repeated fields.");
344 verifyType(descriptor.getLiteType(), value);
346 final Object existingValue = getField(descriptor);
348 if (existingValue == null) {
349 list = new ArrayList<Object>();
350 fields.put(descriptor, list);
352 list = (List<Object>) existingValue;
359 * Verifies that the given object is of the correct type to be a valid
360 * value for the given field. (For repeated fields, this checks if the
361 * object is the right type to be one element of the field.)
363 * @throws IllegalArgumentException The value is not of the right type.
365 private static void verifyType(final WireFormat.FieldType type,
366 final Object value) {
368 throw new NullPointerException();
371 boolean isValid = false;
372 switch (type.getJavaType()) {
373 case INT: isValid = value instanceof Integer ; break;
374 case LONG: isValid = value instanceof Long ; break;
375 case FLOAT: isValid = value instanceof Float ; break;
376 case DOUBLE: isValid = value instanceof Double ; break;
377 case BOOLEAN: isValid = value instanceof Boolean ; break;
378 case STRING: isValid = value instanceof String ; break;
379 case BYTE_STRING: isValid = value instanceof ByteString; break;
381 // TODO(kenton): Caller must do type checking here, I guess.
382 isValid = value instanceof Internal.EnumLite;
385 // TODO(kenton): Caller must do type checking here, I guess.
387 (value instanceof MessageLite) || (value instanceof LazyField);
392 // TODO(kenton): When chaining calls to setField(), it can be hard to
393 // tell from the stack trace which exact call failed, since the whole
394 // chain is considered one line of code. It would be nice to print
395 // more information here, e.g. naming the field. We used to do that.
396 // But we can't now that FieldSet doesn't use descriptors. Maybe this
397 // isn't a big deal, though, since it would only really apply when using
398 // reflection and generally people don't chain reflection setters.
399 throw new IllegalArgumentException(
400 "Wrong object type used with protocol message reflection.");
404 // =================================================================
405 // Parsing and serialization
408 * See {@link Message#isInitialized()}. Note: Since {@code FieldSet}
409 * itself does not have any way of knowing about required fields that
410 * aren't actually present in the set, it is up to the caller to check
411 * that all required fields are present.
413 public boolean isInitialized() {
414 for (int i = 0; i < fields.getNumArrayEntries(); i++) {
415 if (!isInitialized(fields.getArrayEntryAt(i))) {
419 for (final Map.Entry<FieldDescriptorType, Object> entry :
420 fields.getOverflowEntries()) {
421 if (!isInitialized(entry)) {
428 @SuppressWarnings("unchecked")
429 private boolean isInitialized(
430 final Map.Entry<FieldDescriptorType, Object> entry) {
431 final FieldDescriptorType descriptor = entry.getKey();
432 if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
433 if (descriptor.isRepeated()) {
434 for (final MessageLite element:
435 (List<MessageLite>) entry.getValue()) {
436 if (!element.isInitialized()) {
441 Object value = entry.getValue();
442 if (value instanceof MessageLite) {
443 if (!((MessageLite) value).isInitialized()) {
446 } else if (value instanceof LazyField) {
449 throw new IllegalArgumentException(
450 "Wrong object type used with protocol message reflection.");
458 * Given a field type, return the wire type.
460 * @returns One of the {@code WIRETYPE_} constants defined in
461 * {@link WireFormat}.
463 static int getWireFormatForFieldType(final WireFormat.FieldType type,
466 return WireFormat.WIRETYPE_LENGTH_DELIMITED;
468 return type.getWireType();
473 * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another
476 public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
477 for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
478 mergeFromField(other.fields.getArrayEntryAt(i));
480 for (final Map.Entry<FieldDescriptorType, Object> entry :
481 other.fields.getOverflowEntries()) {
482 mergeFromField(entry);
486 @SuppressWarnings({"unchecked", "rawtypes"})
487 private void mergeFromField(
488 final Map.Entry<FieldDescriptorType, Object> entry) {
489 final FieldDescriptorType descriptor = entry.getKey();
490 Object otherValue = entry.getValue();
491 if (otherValue instanceof LazyField) {
492 otherValue = ((LazyField) otherValue).getValue();
495 if (descriptor.isRepeated()) {
496 Object value = getField(descriptor);
498 // Our list is empty, but we still need to make a defensive copy of
499 // the other list since we don't know if the other FieldSet is still
501 fields.put(descriptor, new ArrayList((List) otherValue));
503 // Concatenate the lists.
504 ((List) value).addAll((List) otherValue);
506 } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
507 Object value = getField(descriptor);
509 fields.put(descriptor, otherValue);
511 // Merge the messages.
514 descriptor.internalMergeFrom(
515 ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
519 fields.put(descriptor, otherValue);
523 // TODO(kenton): Move static parsing and serialization methods into some
524 // other class. Probably WireFormat.
527 * Read a field of any primitive type from a CodedInputStream. Enums,
528 * groups, and embedded messages are not handled by this method.
530 * @param input The stream from which to read.
531 * @param type Declared type of the field.
532 * @return An object representing the field's value, of the exact
533 * type which would be returned by
534 * {@link Message#getField(Descriptors.FieldDescriptor)} for
537 public static Object readPrimitiveField(
538 CodedInputStream input,
539 final WireFormat.FieldType type) throws IOException {
541 case DOUBLE : return input.readDouble ();
542 case FLOAT : return input.readFloat ();
543 case INT64 : return input.readInt64 ();
544 case UINT64 : return input.readUInt64 ();
545 case INT32 : return input.readInt32 ();
546 case FIXED64 : return input.readFixed64 ();
547 case FIXED32 : return input.readFixed32 ();
548 case BOOL : return input.readBool ();
549 case STRING : return input.readString ();
550 case BYTES : return input.readBytes ();
551 case UINT32 : return input.readUInt32 ();
552 case SFIXED32: return input.readSFixed32();
553 case SFIXED64: return input.readSFixed64();
554 case SINT32 : return input.readSInt32 ();
555 case SINT64 : return input.readSInt64 ();
558 throw new IllegalArgumentException(
559 "readPrimitiveField() cannot handle nested groups.");
561 throw new IllegalArgumentException(
562 "readPrimitiveField() cannot handle embedded messages.");
564 // We don't handle enums because we don't know what to do if the
565 // value is not recognized.
566 throw new IllegalArgumentException(
567 "readPrimitiveField() cannot handle enums.");
570 throw new RuntimeException(
571 "There is no way to get here, but the compiler thinks otherwise.");
574 /** See {@link Message#writeTo(CodedOutputStream)}. */
575 public void writeTo(final CodedOutputStream output)
577 for (int i = 0; i < fields.getNumArrayEntries(); i++) {
578 final Map.Entry<FieldDescriptorType, Object> entry =
579 fields.getArrayEntryAt(i);
580 writeField(entry.getKey(), entry.getValue(), output);
582 for (final Map.Entry<FieldDescriptorType, Object> entry :
583 fields.getOverflowEntries()) {
584 writeField(entry.getKey(), entry.getValue(), output);
589 * Like {@link #writeTo} but uses MessageSet wire format.
591 public void writeMessageSetTo(final CodedOutputStream output)
593 for (int i = 0; i < fields.getNumArrayEntries(); i++) {
594 writeMessageSetTo(fields.getArrayEntryAt(i), output);
596 for (final Map.Entry<FieldDescriptorType, Object> entry :
597 fields.getOverflowEntries()) {
598 writeMessageSetTo(entry, output);
602 private void writeMessageSetTo(
603 final Map.Entry<FieldDescriptorType, Object> entry,
604 final CodedOutputStream output) throws IOException {
605 final FieldDescriptorType descriptor = entry.getKey();
606 if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
607 !descriptor.isRepeated() && !descriptor.isPacked()) {
608 output.writeMessageSetExtension(entry.getKey().getNumber(),
609 (MessageLite) entry.getValue());
611 writeField(descriptor, entry.getValue(), output);
616 * Write a single tag-value pair to the stream.
618 * @param output The output stream.
619 * @param type The field's type.
620 * @param number The field's number.
621 * @param value Object representing the field's value. Must be of the exact
622 * type which would be returned by
623 * {@link Message#getField(Descriptors.FieldDescriptor)} for
626 private static void writeElement(final CodedOutputStream output,
627 final WireFormat.FieldType type,
629 final Object value) throws IOException {
630 // Special case for groups, which need a start and end tag; other fields
631 // can just use writeTag() and writeFieldNoTag().
632 if (type == WireFormat.FieldType.GROUP) {
633 output.writeGroup(number, (MessageLite) value);
635 output.writeTag(number, getWireFormatForFieldType(type, false));
636 writeElementNoTag(output, type, value);
641 * Write a field of arbitrary type, without its tag, to the stream.
643 * @param output The output stream.
644 * @param type The field's type.
645 * @param value Object representing the field's value. Must be of the exact
646 * type which would be returned by
647 * {@link Message#getField(Descriptors.FieldDescriptor)} for
650 private static void writeElementNoTag(
651 final CodedOutputStream output,
652 final WireFormat.FieldType type,
653 final Object value) throws IOException {
655 case DOUBLE : output.writeDoubleNoTag ((Double ) value); break;
656 case FLOAT : output.writeFloatNoTag ((Float ) value); break;
657 case INT64 : output.writeInt64NoTag ((Long ) value); break;
658 case UINT64 : output.writeUInt64NoTag ((Long ) value); break;
659 case INT32 : output.writeInt32NoTag ((Integer ) value); break;
660 case FIXED64 : output.writeFixed64NoTag ((Long ) value); break;
661 case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break;
662 case BOOL : output.writeBoolNoTag ((Boolean ) value); break;
663 case STRING : output.writeStringNoTag ((String ) value); break;
664 case GROUP : output.writeGroupNoTag ((MessageLite) value); break;
665 case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
666 case BYTES : output.writeBytesNoTag ((ByteString ) value); break;
667 case UINT32 : output.writeUInt32NoTag ((Integer ) value); break;
668 case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break;
669 case SFIXED64: output.writeSFixed64NoTag((Long ) value); break;
670 case SINT32 : output.writeSInt32NoTag ((Integer ) value); break;
671 case SINT64 : output.writeSInt64NoTag ((Long ) value); break;
674 output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
679 /** Write a single field. */
680 public static void writeField(final FieldDescriptorLite<?> descriptor,
682 final CodedOutputStream output)
684 WireFormat.FieldType type = descriptor.getLiteType();
685 int number = descriptor.getNumber();
686 if (descriptor.isRepeated()) {
687 final List<?> valueList = (List<?>)value;
688 if (descriptor.isPacked()) {
689 output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
690 // Compute the total data size so the length can be written.
692 for (final Object element : valueList) {
693 dataSize += computeElementSizeNoTag(type, element);
695 output.writeRawVarint32(dataSize);
696 // Write the data itself, without any tags.
697 for (final Object element : valueList) {
698 writeElementNoTag(output, type, element);
701 for (final Object element : valueList) {
702 writeElement(output, type, number, element);
706 if (value instanceof LazyField) {
707 writeElement(output, type, number, ((LazyField) value).getValue());
709 writeElement(output, type, number, value);
715 * See {@link Message#getSerializedSize()}. It's up to the caller to cache
716 * the resulting size if desired.
718 public int getSerializedSize() {
720 for (int i = 0; i < fields.getNumArrayEntries(); i++) {
721 final Map.Entry<FieldDescriptorType, Object> entry =
722 fields.getArrayEntryAt(i);
723 size += computeFieldSize(entry.getKey(), entry.getValue());
725 for (final Map.Entry<FieldDescriptorType, Object> entry :
726 fields.getOverflowEntries()) {
727 size += computeFieldSize(entry.getKey(), entry.getValue());
733 * Like {@link #getSerializedSize} but uses MessageSet wire format.
735 public int getMessageSetSerializedSize() {
737 for (int i = 0; i < fields.getNumArrayEntries(); i++) {
738 size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
740 for (final Map.Entry<FieldDescriptorType, Object> entry :
741 fields.getOverflowEntries()) {
742 size += getMessageSetSerializedSize(entry);
747 private int getMessageSetSerializedSize(
748 final Map.Entry<FieldDescriptorType, Object> entry) {
749 final FieldDescriptorType descriptor = entry.getKey();
750 Object value = entry.getValue();
751 if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
752 && !descriptor.isRepeated() && !descriptor.isPacked()) {
753 if (value instanceof LazyField) {
754 return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
755 entry.getKey().getNumber(), (LazyField) value);
757 return CodedOutputStream.computeMessageSetExtensionSize(
758 entry.getKey().getNumber(), (MessageLite) value);
761 return computeFieldSize(descriptor, value);
766 * Compute the number of bytes that would be needed to encode a
767 * single tag/value pair of arbitrary type.
769 * @param type The field's type.
770 * @param number The field's number.
771 * @param value Object representing the field's value. Must be of the exact
772 * type which would be returned by
773 * {@link Message#getField(Descriptors.FieldDescriptor)} for
776 private static int computeElementSize(
777 final WireFormat.FieldType type,
778 final int number, final Object value) {
779 int tagSize = CodedOutputStream.computeTagSize(number);
780 if (type == WireFormat.FieldType.GROUP) {
783 return tagSize + computeElementSizeNoTag(type, value);
787 * Compute the number of bytes that would be needed to encode a
788 * particular value of arbitrary type, excluding tag.
790 * @param type The field's type.
791 * @param value Object representing the field's value. Must be of the exact
792 * type which would be returned by
793 * {@link Message#getField(Descriptors.FieldDescriptor)} for
796 private static int computeElementSizeNoTag(
797 final WireFormat.FieldType type, final Object value) {
799 // Note: Minor violation of 80-char limit rule here because this would
800 // actually be harder to read if we wrapped the lines.
801 case DOUBLE : return CodedOutputStream.computeDoubleSizeNoTag ((Double )value);
802 case FLOAT : return CodedOutputStream.computeFloatSizeNoTag ((Float )value);
803 case INT64 : return CodedOutputStream.computeInt64SizeNoTag ((Long )value);
804 case UINT64 : return CodedOutputStream.computeUInt64SizeNoTag ((Long )value);
805 case INT32 : return CodedOutputStream.computeInt32SizeNoTag ((Integer )value);
806 case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value);
807 case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value);
808 case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value);
809 case STRING : return CodedOutputStream.computeStringSizeNoTag ((String )value);
810 case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value);
811 case BYTES : return CodedOutputStream.computeBytesSizeNoTag ((ByteString )value);
812 case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value);
813 case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value);
814 case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value);
815 case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value);
816 case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value);
819 if (value instanceof LazyField) {
820 return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
822 return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
826 return CodedOutputStream.computeEnumSizeNoTag(
827 ((Internal.EnumLite) value).getNumber());
830 throw new RuntimeException(
831 "There is no way to get here, but the compiler thinks otherwise.");
835 * Compute the number of bytes needed to encode a particular field.
837 public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
838 final Object value) {
839 WireFormat.FieldType type = descriptor.getLiteType();
840 int number = descriptor.getNumber();
841 if (descriptor.isRepeated()) {
842 if (descriptor.isPacked()) {
844 for (final Object element : (List<?>)value) {
845 dataSize += computeElementSizeNoTag(type, element);
848 CodedOutputStream.computeTagSize(number) +
849 CodedOutputStream.computeRawVarint32Size(dataSize);
852 for (final Object element : (List<?>)value) {
853 size += computeElementSize(type, number, element);
858 return computeElementSize(type, number, value);