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