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