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