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 com.google.protobuf.LazyField.LazyIterator; 34 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; 40 import java.util.Map; 41 42 /** 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}. 47 * 48 * @author kenton (at) google.com Kenton Varda 49 */ 50 final class FieldSet<FieldDescriptorType extends 51 FieldSet.FieldDescriptorLite<FieldDescriptorType>> { 52 /** 53 * Interface for a FieldDescriptor or lite extension descriptor. This 54 * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}. 55 */ 56 public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>> 57 extends Comparable<T> { 58 int getNumber(); 59 WireFormat.FieldType getLiteType(); 60 WireFormat.JavaType getLiteJavaType(); 61 boolean isRepeated(); 62 boolean isPacked(); 63 Internal.EnumLiteMap<?> getEnumType(); 64 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); 69 } 70 71 private final SmallSortedMap<FieldDescriptorType, Object> fields; 72 private boolean isImmutable; 73 private boolean hasLazyField = false; 74 75 /** Construct a new FieldSet. */ 76 private FieldSet() { 77 this.fields = SmallSortedMap.newFieldMap(16); 78 } 79 80 /** 81 * Construct an empty FieldSet. This is only used to initialize 82 * DEFAULT_INSTANCE. 83 */ 84 private FieldSet(final boolean dummy) { 85 this.fields = SmallSortedMap.newFieldMap(0); 86 makeImmutable(); 87 } 88 89 /** Construct a new FieldSet. */ 90 public static <T extends FieldSet.FieldDescriptorLite<T>> 91 FieldSet<T> newFieldSet() { 92 return new FieldSet<T>(); 93 } 94 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; 100 } 101 @SuppressWarnings("rawtypes") 102 private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true); 103 104 /** Make this FieldSet immutable from this point forward. */ 105 @SuppressWarnings("unchecked") 106 public void makeImmutable() { 107 if (isImmutable) { 108 return; 109 } 110 fields.makeImmutable(); 111 isImmutable = true; 112 } 113 114 /** 115 * Returns whether the FieldSet is immutable. This is true if it is the 116 * {@link #emptySet} or if {@link #makeImmutable} were called. 117 * 118 * @return whether the FieldSet is immutable. 119 */ 120 public boolean isImmutable() { 121 return isImmutable; 122 } 123 124 @Override 125 public boolean equals(Object o) { 126 if (this == o) { 127 return true; 128 } 129 130 if (!(o instanceof FieldSet)) { 131 return false; 132 } 133 134 FieldSet<?> other = (FieldSet<?>) o; 135 return other.fields.equals(other.fields); 136 } 137 138 @Override 139 public int hashCode() { 140 return fields.hashCode(); 141 } 142 143 /** 144 * Clones the FieldSet. The returned FieldSet will be mutable even if the 145 * original FieldSet was immutable. 146 * 147 * @return the newly cloned FieldSet 148 */ 149 @Override 150 public FieldSet<FieldDescriptorType> clone() { 151 // We can't just call fields.clone because List objects in the map 152 // should not be shared. 153 FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet(); 154 for (int i = 0; i < fields.getNumArrayEntries(); i++) { 155 Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i); 156 FieldDescriptorType descriptor = entry.getKey(); 157 clone.setField(descriptor, entry.getValue()); 158 } 159 for (Map.Entry<FieldDescriptorType, Object> entry : 160 fields.getOverflowEntries()) { 161 FieldDescriptorType descriptor = entry.getKey(); 162 clone.setField(descriptor, entry.getValue()); 163 } 164 clone.hasLazyField = hasLazyField; 165 return clone; 166 } 167 168 169 // ================================================================= 170 171 /** See {@link Message.Builder#clear()}. */ 172 public void clear() { 173 fields.clear(); 174 hasLazyField = false; 175 } 176 177 /** 178 * Get a simple map containing all the fields. 179 */ 180 public Map<FieldDescriptorType, Object> getAllFields() { 181 if (hasLazyField) { 182 SmallSortedMap<FieldDescriptorType, Object> result = 183 SmallSortedMap.newFieldMap(16); 184 for (int i = 0; i < fields.getNumArrayEntries(); i++) { 185 cloneFieldEntry(result, fields.getArrayEntryAt(i)); 186 } 187 for (Map.Entry<FieldDescriptorType, Object> entry : 188 fields.getOverflowEntries()) { 189 cloneFieldEntry(result, entry); 190 } 191 if (fields.isImmutable()) { 192 result.makeImmutable(); 193 } 194 return result; 195 } 196 return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields); 197 } 198 199 private void cloneFieldEntry(Map<FieldDescriptorType, Object> map, 200 Map.Entry<FieldDescriptorType, Object> entry) { 201 FieldDescriptorType key = entry.getKey(); 202 Object value = entry.getValue(); 203 if (value instanceof LazyField) { 204 map.put(key, ((LazyField) value).getValue()); 205 } else { 206 map.put(key, value); 207 } 208 } 209 210 /** 211 * Get an iterator to the field map. This iterator should not be leaked out 212 * of the protobuf library as it is not protected from mutation when fields 213 * is not immutable. 214 */ 215 public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() { 216 if (hasLazyField) { 217 return new LazyIterator<FieldDescriptorType>( 218 fields.entrySet().iterator()); 219 } 220 return fields.entrySet().iterator(); 221 } 222 223 /** 224 * Useful for implementing 225 * {@link Message#hasField(Descriptors.FieldDescriptor)}. 226 */ 227 public boolean hasField(final FieldDescriptorType descriptor) { 228 if (descriptor.isRepeated()) { 229 throw new IllegalArgumentException( 230 "hasField() can only be called on non-repeated fields."); 231 } 232 233 return fields.get(descriptor) != null; 234 } 235 236 /** 237 * Useful for implementing 238 * {@link Message#getField(Descriptors.FieldDescriptor)}. This method 239 * returns {@code null} if the field is not set; in this case it is up 240 * to the caller to fetch the field's default value. 241 */ 242 public Object getField(final FieldDescriptorType descriptor) { 243 Object o = fields.get(descriptor); 244 if (o instanceof LazyField) { 245 return ((LazyField) o).getValue(); 246 } 247 return o; 248 } 249 250 /** 251 * Useful for implementing 252 * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}. 253 */ 254 @SuppressWarnings({"unchecked", "rawtypes"}) 255 public void setField(final FieldDescriptorType descriptor, 256 Object value) { 257 if (descriptor.isRepeated()) { 258 if (!(value instanceof List)) { 259 throw new IllegalArgumentException( 260 "Wrong object type used with protocol message reflection."); 261 } 262 263 // Wrap the contents in a new list so that the caller cannot change 264 // the list's contents after setting it. 265 final List newList = new ArrayList(); 266 newList.addAll((List) value); 267 for (final Object element : newList) { 268 verifyType(descriptor.getLiteType(), element); 269 } 270 value = newList; 271 } else { 272 verifyType(descriptor.getLiteType(), value); 273 } 274 275 if (value instanceof LazyField) { 276 hasLazyField = true; 277 } 278 fields.put(descriptor, value); 279 } 280 281 /** 282 * Useful for implementing 283 * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. 284 */ 285 public void clearField(final FieldDescriptorType descriptor) { 286 fields.remove(descriptor); 287 if (fields.isEmpty()) { 288 hasLazyField = false; 289 } 290 } 291 292 /** 293 * Useful for implementing 294 * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}. 295 */ 296 public int getRepeatedFieldCount(final FieldDescriptorType descriptor) { 297 if (!descriptor.isRepeated()) { 298 throw new IllegalArgumentException( 299 "getRepeatedField() can only be called on repeated fields."); 300 } 301 302 final Object value = getField(descriptor); 303 if (value == null) { 304 return 0; 305 } else { 306 return ((List<?>) value).size(); 307 } 308 } 309 310 /** 311 * Useful for implementing 312 * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}. 313 */ 314 public Object getRepeatedField(final FieldDescriptorType descriptor, 315 final int index) { 316 if (!descriptor.isRepeated()) { 317 throw new IllegalArgumentException( 318 "getRepeatedField() can only be called on repeated fields."); 319 } 320 321 final Object value = getField(descriptor); 322 323 if (value == null) { 324 throw new IndexOutOfBoundsException(); 325 } else { 326 return ((List<?>) value).get(index); 327 } 328 } 329 330 /** 331 * Useful for implementing 332 * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}. 333 */ 334 @SuppressWarnings("unchecked") 335 public void setRepeatedField(final FieldDescriptorType descriptor, 336 final int index, 337 final Object value) { 338 if (!descriptor.isRepeated()) { 339 throw new IllegalArgumentException( 340 "getRepeatedField() can only be called on repeated fields."); 341 } 342 343 final Object list = getField(descriptor); 344 if (list == null) { 345 throw new IndexOutOfBoundsException(); 346 } 347 348 verifyType(descriptor.getLiteType(), value); 349 ((List<Object>) list).set(index, value); 350 } 351 352 /** 353 * Useful for implementing 354 * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}. 355 */ 356 @SuppressWarnings("unchecked") 357 public void addRepeatedField(final FieldDescriptorType descriptor, 358 final Object value) { 359 if (!descriptor.isRepeated()) { 360 throw new IllegalArgumentException( 361 "addRepeatedField() can only be called on repeated fields."); 362 } 363 364 verifyType(descriptor.getLiteType(), value); 365 366 final Object existingValue = getField(descriptor); 367 List<Object> list; 368 if (existingValue == null) { 369 list = new ArrayList<Object>(); 370 fields.put(descriptor, list); 371 } else { 372 list = (List<Object>) existingValue; 373 } 374 375 list.add(value); 376 } 377 378 /** 379 * Verifies that the given object is of the correct type to be a valid 380 * value for the given field. (For repeated fields, this checks if the 381 * object is the right type to be one element of the field.) 382 * 383 * @throws IllegalArgumentException The value is not of the right type. 384 */ 385 private static void verifyType(final WireFormat.FieldType type, 386 final Object value) { 387 if (value == null) { 388 throw new NullPointerException(); 389 } 390 391 boolean isValid = false; 392 switch (type.getJavaType()) { 393 case INT: isValid = value instanceof Integer ; break; 394 case LONG: isValid = value instanceof Long ; break; 395 case FLOAT: isValid = value instanceof Float ; break; 396 case DOUBLE: isValid = value instanceof Double ; break; 397 case BOOLEAN: isValid = value instanceof Boolean ; break; 398 case STRING: isValid = value instanceof String ; break; 399 case BYTE_STRING: 400 isValid = value instanceof ByteString || value instanceof byte[]; 401 break; 402 case ENUM: 403 // TODO(kenton): Caller must do type checking here, I guess. 404 isValid = 405 (value instanceof Integer || value instanceof Internal.EnumLite); 406 break; 407 case MESSAGE: 408 // TODO(kenton): Caller must do type checking here, I guess. 409 isValid = 410 (value instanceof MessageLite) || (value instanceof LazyField); 411 break; 412 } 413 414 if (!isValid) { 415 // TODO(kenton): When chaining calls to setField(), it can be hard to 416 // tell from the stack trace which exact call failed, since the whole 417 // chain is considered one line of code. It would be nice to print 418 // more information here, e.g. naming the field. We used to do that. 419 // But we can't now that FieldSet doesn't use descriptors. Maybe this 420 // isn't a big deal, though, since it would only really apply when using 421 // reflection and generally people don't chain reflection setters. 422 throw new IllegalArgumentException( 423 "Wrong object type used with protocol message reflection."); 424 } 425 } 426 427 // ================================================================= 428 // Parsing and serialization 429 430 /** 431 * See {@link Message#isInitialized()}. Note: Since {@code FieldSet} 432 * itself does not have any way of knowing about required fields that 433 * aren't actually present in the set, it is up to the caller to check 434 * that all required fields are present. 435 */ 436 public boolean isInitialized() { 437 for (int i = 0; i < fields.getNumArrayEntries(); i++) { 438 if (!isInitialized(fields.getArrayEntryAt(i))) { 439 return false; 440 } 441 } 442 for (final Map.Entry<FieldDescriptorType, Object> entry : 443 fields.getOverflowEntries()) { 444 if (!isInitialized(entry)) { 445 return false; 446 } 447 } 448 return true; 449 } 450 451 @SuppressWarnings("unchecked") 452 private boolean isInitialized( 453 final Map.Entry<FieldDescriptorType, Object> entry) { 454 final FieldDescriptorType descriptor = entry.getKey(); 455 if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) { 456 if (descriptor.isRepeated()) { 457 for (final MessageLite element: 458 (List<MessageLite>) entry.getValue()) { 459 if (!element.isInitialized()) { 460 return false; 461 } 462 } 463 } else { 464 Object value = entry.getValue(); 465 if (value instanceof MessageLite) { 466 if (!((MessageLite) value).isInitialized()) { 467 return false; 468 } 469 } else if (value instanceof LazyField) { 470 return true; 471 } else { 472 throw new IllegalArgumentException( 473 "Wrong object type used with protocol message reflection."); 474 } 475 } 476 } 477 return true; 478 } 479 480 /** 481 * Given a field type, return the wire type. 482 * 483 * @returns One of the {@code WIRETYPE_} constants defined in 484 * {@link WireFormat}. 485 */ 486 static int getWireFormatForFieldType(final WireFormat.FieldType type, 487 boolean isPacked) { 488 if (isPacked) { 489 return WireFormat.WIRETYPE_LENGTH_DELIMITED; 490 } else { 491 return type.getWireType(); 492 } 493 } 494 495 /** 496 * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another 497 * {@link FieldSet}. 498 */ 499 public void mergeFrom(final FieldSet<FieldDescriptorType> other) { 500 for (int i = 0; i < other.fields.getNumArrayEntries(); i++) { 501 mergeFromField(other.fields.getArrayEntryAt(i)); 502 } 503 for (final Map.Entry<FieldDescriptorType, Object> entry : 504 other.fields.getOverflowEntries()) { 505 mergeFromField(entry); 506 } 507 } 508 509 private Object cloneIfMutable(Object value) { 510 if (value instanceof byte[]) { 511 byte[] bytes = (byte[]) value; 512 byte[] copy = new byte[bytes.length]; 513 System.arraycopy(bytes, 0, copy, 0, bytes.length); 514 return copy; 515 } else { 516 return value; 517 } 518 } 519 520 @SuppressWarnings({"unchecked", "rawtypes"}) 521 private void mergeFromField( 522 final Map.Entry<FieldDescriptorType, Object> entry) { 523 final FieldDescriptorType descriptor = entry.getKey(); 524 Object otherValue = entry.getValue(); 525 if (otherValue instanceof LazyField) { 526 otherValue = ((LazyField) otherValue).getValue(); 527 } 528 529 if (descriptor.isRepeated()) { 530 Object value = getField(descriptor); 531 if (value == null) { 532 value = new ArrayList(); 533 } 534 for (Object element : (List) otherValue) { 535 ((List) value).add(cloneIfMutable(element)); 536 } 537 fields.put(descriptor, value); 538 } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) { 539 Object value = getField(descriptor); 540 if (value == null) { 541 fields.put(descriptor, cloneIfMutable(otherValue)); 542 } else { 543 // Merge the messages. 544 value = descriptor.internalMergeFrom( 545 ((MessageLite) value).toBuilder(), (MessageLite) otherValue) 546 .build(); 547 548 fields.put(descriptor, value); 549 } 550 } else { 551 fields.put(descriptor, cloneIfMutable(otherValue)); 552 } 553 } 554 555 // TODO(kenton): Move static parsing and serialization methods into some 556 // other class. Probably WireFormat. 557 558 /** 559 * Read a field of any primitive type for immutable messages from a 560 * CodedInputStream. Enums, groups, and embedded messages are not handled by 561 * this method. 562 * 563 * @param input The stream from which to read. 564 * @param type Declared type of the field. 565 * @param checkUtf8 When true, check that the input is valid utf8. 566 * @return An object representing the field's value, of the exact 567 * type which would be returned by 568 * {@link Message#getField(Descriptors.FieldDescriptor)} for 569 * this field. 570 */ 571 public static Object readPrimitiveField( 572 CodedInputStream input, 573 final WireFormat.FieldType type, 574 boolean checkUtf8) throws IOException { 575 if (checkUtf8) { 576 return WireFormat.readPrimitiveField(input, type, 577 WireFormat.Utf8Validation.STRICT); 578 } else { 579 return WireFormat.readPrimitiveField(input, type, 580 WireFormat.Utf8Validation.LOOSE); 581 } 582 } 583 584 585 /** See {@link Message#writeTo(CodedOutputStream)}. */ 586 public void writeTo(final CodedOutputStream output) 587 throws IOException { 588 for (int i = 0; i < fields.getNumArrayEntries(); i++) { 589 final Map.Entry<FieldDescriptorType, Object> entry = 590 fields.getArrayEntryAt(i); 591 writeField(entry.getKey(), entry.getValue(), output); 592 } 593 for (final Map.Entry<FieldDescriptorType, Object> entry : 594 fields.getOverflowEntries()) { 595 writeField(entry.getKey(), entry.getValue(), output); 596 } 597 } 598 599 /** 600 * Like {@link #writeTo} but uses MessageSet wire format. 601 */ 602 public void writeMessageSetTo(final CodedOutputStream output) 603 throws IOException { 604 for (int i = 0; i < fields.getNumArrayEntries(); i++) { 605 writeMessageSetTo(fields.getArrayEntryAt(i), output); 606 } 607 for (final Map.Entry<FieldDescriptorType, Object> entry : 608 fields.getOverflowEntries()) { 609 writeMessageSetTo(entry, output); 610 } 611 } 612 613 private void writeMessageSetTo( 614 final Map.Entry<FieldDescriptorType, Object> entry, 615 final CodedOutputStream output) throws IOException { 616 final FieldDescriptorType descriptor = entry.getKey(); 617 if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE && 618 !descriptor.isRepeated() && !descriptor.isPacked()) { 619 Object value = entry.getValue(); 620 if (value instanceof LazyField) { 621 value = ((LazyField) value).getValue(); 622 } 623 output.writeMessageSetExtension(entry.getKey().getNumber(), 624 (MessageLite) value); 625 } else { 626 writeField(descriptor, entry.getValue(), output); 627 } 628 } 629 630 /** 631 * Write a single tag-value pair to the stream. 632 * 633 * @param output The output stream. 634 * @param type The field's type. 635 * @param number The field's number. 636 * @param value Object representing the field's value. Must be of the exact 637 * type which would be returned by 638 * {@link Message#getField(Descriptors.FieldDescriptor)} for 639 * this field. 640 */ 641 private static void writeElement(final CodedOutputStream output, 642 final WireFormat.FieldType type, 643 final int number, 644 final Object value) throws IOException { 645 // Special case for groups, which need a start and end tag; other fields 646 // can just use writeTag() and writeFieldNoTag(). 647 if (type == WireFormat.FieldType.GROUP) { 648 output.writeGroup(number, (MessageLite) value); 649 } else { 650 output.writeTag(number, getWireFormatForFieldType(type, false)); 651 writeElementNoTag(output, type, value); 652 } 653 } 654 655 /** 656 * Write a field of arbitrary type, without its tag, to the stream. 657 * 658 * @param output The output stream. 659 * @param type The field's type. 660 * @param value Object representing the field's value. Must be of the exact 661 * type which would be returned by 662 * {@link Message#getField(Descriptors.FieldDescriptor)} for 663 * this field. 664 */ 665 static void writeElementNoTag( 666 final CodedOutputStream output, 667 final WireFormat.FieldType type, 668 final Object value) throws IOException { 669 switch (type) { 670 case DOUBLE : output.writeDoubleNoTag ((Double ) value); break; 671 case FLOAT : output.writeFloatNoTag ((Float ) value); break; 672 case INT64 : output.writeInt64NoTag ((Long ) value); break; 673 case UINT64 : output.writeUInt64NoTag ((Long ) value); break; 674 case INT32 : output.writeInt32NoTag ((Integer ) value); break; 675 case FIXED64 : output.writeFixed64NoTag ((Long ) value); break; 676 case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break; 677 case BOOL : output.writeBoolNoTag ((Boolean ) value); break; 678 case GROUP : output.writeGroupNoTag ((MessageLite) value); break; 679 case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break; 680 case STRING: 681 if (value instanceof ByteString) { 682 output.writeBytesNoTag((ByteString) value); 683 } else { 684 output.writeStringNoTag((String) value); 685 } 686 break; 687 case BYTES: 688 if (value instanceof ByteString) { 689 output.writeBytesNoTag((ByteString) value); 690 } else { 691 output.writeByteArrayNoTag((byte[]) value); 692 } 693 break; 694 case UINT32 : output.writeUInt32NoTag ((Integer ) value); break; 695 case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break; 696 case SFIXED64: output.writeSFixed64NoTag((Long ) value); break; 697 case SINT32 : output.writeSInt32NoTag ((Integer ) value); break; 698 case SINT64 : output.writeSInt64NoTag ((Long ) value); break; 699 700 case ENUM: 701 if (value instanceof Internal.EnumLite) { 702 output.writeEnumNoTag(((Internal.EnumLite) value).getNumber()); 703 } else { 704 output.writeEnumNoTag(((Integer) value).intValue()); 705 } 706 break; 707 } 708 } 709 710 /** Write a single field. */ 711 public static void writeField(final FieldDescriptorLite<?> descriptor, 712 final Object value, 713 final CodedOutputStream output) 714 throws IOException { 715 WireFormat.FieldType type = descriptor.getLiteType(); 716 int number = descriptor.getNumber(); 717 if (descriptor.isRepeated()) { 718 final List<?> valueList = (List<?>)value; 719 if (descriptor.isPacked()) { 720 output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED); 721 // Compute the total data size so the length can be written. 722 int dataSize = 0; 723 for (final Object element : valueList) { 724 dataSize += computeElementSizeNoTag(type, element); 725 } 726 output.writeRawVarint32(dataSize); 727 // Write the data itself, without any tags. 728 for (final Object element : valueList) { 729 writeElementNoTag(output, type, element); 730 } 731 } else { 732 for (final Object element : valueList) { 733 writeElement(output, type, number, element); 734 } 735 } 736 } else { 737 if (value instanceof LazyField) { 738 writeElement(output, type, number, ((LazyField) value).getValue()); 739 } else { 740 writeElement(output, type, number, value); 741 } 742 } 743 } 744 745 /** 746 * See {@link Message#getSerializedSize()}. It's up to the caller to cache 747 * the resulting size if desired. 748 */ 749 public int getSerializedSize() { 750 int size = 0; 751 for (int i = 0; i < fields.getNumArrayEntries(); i++) { 752 final Map.Entry<FieldDescriptorType, Object> entry = 753 fields.getArrayEntryAt(i); 754 size += computeFieldSize(entry.getKey(), entry.getValue()); 755 } 756 for (final Map.Entry<FieldDescriptorType, Object> entry : 757 fields.getOverflowEntries()) { 758 size += computeFieldSize(entry.getKey(), entry.getValue()); 759 } 760 return size; 761 } 762 763 /** 764 * Like {@link #getSerializedSize} but uses MessageSet wire format. 765 */ 766 public int getMessageSetSerializedSize() { 767 int size = 0; 768 for (int i = 0; i < fields.getNumArrayEntries(); i++) { 769 size += getMessageSetSerializedSize(fields.getArrayEntryAt(i)); 770 } 771 for (final Map.Entry<FieldDescriptorType, Object> entry : 772 fields.getOverflowEntries()) { 773 size += getMessageSetSerializedSize(entry); 774 } 775 return size; 776 } 777 778 private int getMessageSetSerializedSize( 779 final Map.Entry<FieldDescriptorType, Object> entry) { 780 final FieldDescriptorType descriptor = entry.getKey(); 781 Object value = entry.getValue(); 782 if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE 783 && !descriptor.isRepeated() && !descriptor.isPacked()) { 784 if (value instanceof LazyField) { 785 return CodedOutputStream.computeLazyFieldMessageSetExtensionSize( 786 entry.getKey().getNumber(), (LazyField) value); 787 } else { 788 return CodedOutputStream.computeMessageSetExtensionSize( 789 entry.getKey().getNumber(), (MessageLite) value); 790 } 791 } else { 792 return computeFieldSize(descriptor, value); 793 } 794 } 795 796 /** 797 * Compute the number of bytes that would be needed to encode a 798 * single tag/value pair of arbitrary type. 799 * 800 * @param type The field's type. 801 * @param number The field's number. 802 * @param value Object representing the field's value. Must be of the exact 803 * type which would be returned by 804 * {@link Message#getField(Descriptors.FieldDescriptor)} for 805 * this field. 806 */ 807 private static int computeElementSize( 808 final WireFormat.FieldType type, 809 final int number, final Object value) { 810 int tagSize = CodedOutputStream.computeTagSize(number); 811 if (type == WireFormat.FieldType.GROUP) { 812 // Only count the end group tag for proto2 messages as for proto1 the end 813 // group tag will be counted as a part of getSerializedSize(). 814 tagSize *= 2; 815 } 816 return tagSize + computeElementSizeNoTag(type, value); 817 } 818 819 /** 820 * Compute the number of bytes that would be needed to encode a 821 * particular value of arbitrary type, excluding tag. 822 * 823 * @param type The field's type. 824 * @param value Object representing the field's value. Must be of the exact 825 * type which would be returned by 826 * {@link Message#getField(Descriptors.FieldDescriptor)} for 827 * this field. 828 */ 829 static int computeElementSizeNoTag( 830 final WireFormat.FieldType type, final Object value) { 831 switch (type) { 832 // Note: Minor violation of 80-char limit rule here because this would 833 // actually be harder to read if we wrapped the lines. 834 case DOUBLE : return CodedOutputStream.computeDoubleSizeNoTag ((Double )value); 835 case FLOAT : return CodedOutputStream.computeFloatSizeNoTag ((Float )value); 836 case INT64 : return CodedOutputStream.computeInt64SizeNoTag ((Long )value); 837 case UINT64 : return CodedOutputStream.computeUInt64SizeNoTag ((Long )value); 838 case INT32 : return CodedOutputStream.computeInt32SizeNoTag ((Integer )value); 839 case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value); 840 case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value); 841 case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value); 842 case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value); 843 case BYTES : 844 if (value instanceof ByteString) { 845 return CodedOutputStream.computeBytesSizeNoTag((ByteString) value); 846 } else { 847 return CodedOutputStream.computeByteArraySizeNoTag((byte[]) value); 848 } 849 case STRING : 850 if (value instanceof ByteString) { 851 return CodedOutputStream.computeBytesSizeNoTag((ByteString) value); 852 } else { 853 return CodedOutputStream.computeStringSizeNoTag((String) value); 854 } 855 case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value); 856 case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value); 857 case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value); 858 case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value); 859 case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value); 860 861 case MESSAGE: 862 if (value instanceof LazyField) { 863 return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value); 864 } else { 865 return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value); 866 } 867 868 case ENUM: 869 if (value instanceof Internal.EnumLite) { 870 return CodedOutputStream.computeEnumSizeNoTag( 871 ((Internal.EnumLite) value).getNumber()); 872 } else { 873 return CodedOutputStream.computeEnumSizeNoTag((Integer) value); 874 } 875 } 876 877 throw new RuntimeException( 878 "There is no way to get here, but the compiler thinks otherwise."); 879 } 880 881 /** 882 * Compute the number of bytes needed to encode a particular field. 883 */ 884 public static int computeFieldSize(final FieldDescriptorLite<?> descriptor, 885 final Object value) { 886 WireFormat.FieldType type = descriptor.getLiteType(); 887 int number = descriptor.getNumber(); 888 if (descriptor.isRepeated()) { 889 if (descriptor.isPacked()) { 890 int dataSize = 0; 891 for (final Object element : (List<?>)value) { 892 dataSize += computeElementSizeNoTag(type, element); 893 } 894 return dataSize + 895 CodedOutputStream.computeTagSize(number) + 896 CodedOutputStream.computeRawVarint32Size(dataSize); 897 } else { 898 int size = 0; 899 for (final Object element : (List<?>)value) { 900 size += computeElementSize(type, number, element); 901 } 902 return size; 903 } 904 } else { 905 return computeElementSize(type, number, value); 906 } 907 } 908 } 909