1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import com.google.protobuf.Descriptors.Descriptor; 34 import com.google.protobuf.Descriptors.FieldDescriptor; 35 import com.google.protobuf.GeneratedMessage.ExtendableBuilder; 36 import com.google.protobuf.Internal.EnumLite; 37 38 import java.io.IOException; 39 import java.io.InputStream; 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.Map; 43 44 /** 45 * A partial implementation of the {@link Message} interface which implements 46 * as many methods of that interface as possible in terms of other methods. 47 * 48 * @author kenton (at) google.com Kenton Varda 49 */ 50 public abstract class AbstractMessage extends AbstractMessageLite 51 implements Message { 52 @SuppressWarnings("unchecked") 53 public boolean isInitialized() { 54 // Check that all required fields are present. 55 for (final FieldDescriptor field : getDescriptorForType().getFields()) { 56 if (field.isRequired()) { 57 if (!hasField(field)) { 58 return false; 59 } 60 } 61 } 62 63 // Check that embedded messages are initialized. 64 for (final Map.Entry<FieldDescriptor, Object> entry : 65 getAllFields().entrySet()) { 66 final FieldDescriptor field = entry.getKey(); 67 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 68 if (field.isRepeated()) { 69 for (final Message element : (List<Message>) entry.getValue()) { 70 if (!element.isInitialized()) { 71 return false; 72 } 73 } 74 } else { 75 if (!((Message) entry.getValue()).isInitialized()) { 76 return false; 77 } 78 } 79 } 80 } 81 82 return true; 83 } 84 85 public List<String> findInitializationErrors() { 86 return Builder.findMissingFields(this); 87 } 88 89 public String getInitializationErrorString() { 90 return delimitWithCommas(findInitializationErrors()); 91 } 92 93 private static String delimitWithCommas(List<String> parts) { 94 StringBuilder result = new StringBuilder(); 95 for (String part : parts) { 96 if (result.length() > 0) { 97 result.append(", "); 98 } 99 result.append(part); 100 } 101 return result.toString(); 102 } 103 104 @Override 105 public final String toString() { 106 return TextFormat.printToString(this); 107 } 108 109 public void writeTo(final CodedOutputStream output) throws IOException { 110 final boolean isMessageSet = 111 getDescriptorForType().getOptions().getMessageSetWireFormat(); 112 113 for (final Map.Entry<FieldDescriptor, Object> entry : 114 getAllFields().entrySet()) { 115 final FieldDescriptor field = entry.getKey(); 116 final Object value = entry.getValue(); 117 if (isMessageSet && field.isExtension() && 118 field.getType() == FieldDescriptor.Type.MESSAGE && 119 !field.isRepeated()) { 120 output.writeMessageSetExtension(field.getNumber(), (Message) value); 121 } else { 122 FieldSet.writeField(field, value, output); 123 } 124 } 125 126 final UnknownFieldSet unknownFields = getUnknownFields(); 127 if (isMessageSet) { 128 unknownFields.writeAsMessageSetTo(output); 129 } else { 130 unknownFields.writeTo(output); 131 } 132 } 133 134 private int memoizedSize = -1; 135 136 public int getSerializedSize() { 137 int size = memoizedSize; 138 if (size != -1) { 139 return size; 140 } 141 142 size = 0; 143 final boolean isMessageSet = 144 getDescriptorForType().getOptions().getMessageSetWireFormat(); 145 146 for (final Map.Entry<FieldDescriptor, Object> entry : 147 getAllFields().entrySet()) { 148 final FieldDescriptor field = entry.getKey(); 149 final Object value = entry.getValue(); 150 if (isMessageSet && field.isExtension() && 151 field.getType() == FieldDescriptor.Type.MESSAGE && 152 !field.isRepeated()) { 153 size += CodedOutputStream.computeMessageSetExtensionSize( 154 field.getNumber(), (Message) value); 155 } else { 156 size += FieldSet.computeFieldSize(field, value); 157 } 158 } 159 160 final UnknownFieldSet unknownFields = getUnknownFields(); 161 if (isMessageSet) { 162 size += unknownFields.getSerializedSizeAsMessageSet(); 163 } else { 164 size += unknownFields.getSerializedSize(); 165 } 166 167 memoizedSize = size; 168 return size; 169 } 170 171 @Override 172 public boolean equals(final Object other) { 173 if (other == this) { 174 return true; 175 } 176 if (!(other instanceof Message)) { 177 return false; 178 } 179 final Message otherMessage = (Message) other; 180 if (getDescriptorForType() != otherMessage.getDescriptorForType()) { 181 return false; 182 } 183 return getAllFields().equals(otherMessage.getAllFields()) && 184 getUnknownFields().equals(otherMessage.getUnknownFields()); 185 } 186 187 @Override 188 public int hashCode() { 189 int hash = 41; 190 hash = (19 * hash) + getDescriptorForType().hashCode(); 191 hash = hashFields(hash, getAllFields()); 192 hash = (29 * hash) + getUnknownFields().hashCode(); 193 return hash; 194 } 195 196 /** Get a hash code for given fields and values, using the given seed. */ 197 @SuppressWarnings("unchecked") 198 protected int hashFields(int hash, Map<FieldDescriptor, Object> map) { 199 for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) { 200 FieldDescriptor field = entry.getKey(); 201 Object value = entry.getValue(); 202 hash = (37 * hash) + field.getNumber(); 203 if (field.getType() != FieldDescriptor.Type.ENUM){ 204 hash = (53 * hash) + value.hashCode(); 205 } else if (field.isRepeated()) { 206 List<? extends EnumLite> list = (List<? extends EnumLite>) value; 207 hash = (53 * hash) + hashEnumList(list); 208 } else { 209 hash = (53 * hash) + hashEnum((EnumLite) value); 210 } 211 } 212 return hash; 213 } 214 215 /** 216 * Helper method for implementing {@link Message#hashCode()}. 217 * @see Boolean#hashCode() 218 */ 219 protected static int hashLong(long n) { 220 return (int) (n ^ (n >>> 32)); 221 } 222 223 /** 224 * Helper method for implementing {@link Message#hashCode()}. 225 * @see Boolean#hashCode() 226 */ 227 protected static int hashBoolean(boolean b) { 228 return b ? 1231 : 1237; 229 } 230 231 /** 232 * Package private helper method for AbstractParser to create 233 * UninitializedMessageException with missing field information. 234 */ 235 @Override 236 UninitializedMessageException newUninitializedMessageException() { 237 return Builder.newUninitializedMessageException(this); 238 } 239 240 /** 241 * Helper method for implementing {@link Message#hashCode()}. 242 * <p> 243 * This is needed because {@link java.lang.Enum#hashCode()} is final, but we 244 * need to use the field number as the hash code to ensure compatibility 245 * between statically and dynamically generated enum objects. 246 */ 247 protected static int hashEnum(EnumLite e) { 248 return e.getNumber(); 249 } 250 251 /** Helper method for implementing {@link Message#hashCode()}. */ 252 protected static int hashEnumList(List<? extends EnumLite> list) { 253 int hash = 1; 254 for (EnumLite e : list) { 255 hash = 31 * hash + hashEnum(e); 256 } 257 return hash; 258 } 259 260 // ================================================================= 261 262 /** 263 * A partial implementation of the {@link Message.Builder} interface which 264 * implements as many methods of that interface as possible in terms of 265 * other methods. 266 */ 267 @SuppressWarnings("unchecked") 268 public static abstract class Builder<BuilderType extends Builder> 269 extends AbstractMessageLite.Builder<BuilderType> 270 implements Message.Builder { 271 // The compiler produces an error if this is not declared explicitly. 272 @Override 273 public abstract BuilderType clone(); 274 275 public BuilderType clear() { 276 for (final Map.Entry<FieldDescriptor, Object> entry : 277 getAllFields().entrySet()) { 278 clearField(entry.getKey()); 279 } 280 return (BuilderType) this; 281 } 282 283 public List<String> findInitializationErrors() { 284 return findMissingFields(this); 285 } 286 287 public String getInitializationErrorString() { 288 return delimitWithCommas(findInitializationErrors()); 289 } 290 291 public BuilderType mergeFrom(final Message other) { 292 if (other.getDescriptorForType() != getDescriptorForType()) { 293 throw new IllegalArgumentException( 294 "mergeFrom(Message) can only merge messages of the same type."); 295 } 296 297 // Note: We don't attempt to verify that other's fields have valid 298 // types. Doing so would be a losing battle. We'd have to verify 299 // all sub-messages as well, and we'd have to make copies of all of 300 // them to insure that they don't change after verification (since 301 // the Message interface itself cannot enforce immutability of 302 // implementations). 303 // TODO(kenton): Provide a function somewhere called makeDeepCopy() 304 // which allows people to make secure deep copies of messages. 305 306 for (final Map.Entry<FieldDescriptor, Object> entry : 307 other.getAllFields().entrySet()) { 308 final FieldDescriptor field = entry.getKey(); 309 if (field.isRepeated()) { 310 for (final Object element : (List)entry.getValue()) { 311 addRepeatedField(field, element); 312 } 313 } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 314 final Message existingValue = (Message)getField(field); 315 if (existingValue == existingValue.getDefaultInstanceForType()) { 316 setField(field, entry.getValue()); 317 } else { 318 setField(field, 319 existingValue.newBuilderForType() 320 .mergeFrom(existingValue) 321 .mergeFrom((Message)entry.getValue()) 322 .build()); 323 } 324 } else { 325 setField(field, entry.getValue()); 326 } 327 } 328 329 mergeUnknownFields(other.getUnknownFields()); 330 331 return (BuilderType) this; 332 } 333 334 @Override 335 public BuilderType mergeFrom(final CodedInputStream input) 336 throws IOException { 337 return mergeFrom(input, ExtensionRegistry.getEmptyRegistry()); 338 } 339 340 @Override 341 public BuilderType mergeFrom( 342 final CodedInputStream input, 343 final ExtensionRegistryLite extensionRegistry) 344 throws IOException { 345 final UnknownFieldSet.Builder unknownFields = 346 UnknownFieldSet.newBuilder(getUnknownFields()); 347 while (true) { 348 final int tag = input.readTag(); 349 if (tag == 0) { 350 break; 351 } 352 353 if (!mergeFieldFrom(input, unknownFields, extensionRegistry, 354 getDescriptorForType(), this, null, tag)) { 355 // end group tag 356 break; 357 } 358 } 359 setUnknownFields(unknownFields.build()); 360 return (BuilderType) this; 361 } 362 363 /** helper method to handle {@code builder} and {@code extensions}. */ 364 private static void addRepeatedField( 365 Message.Builder builder, 366 FieldSet<FieldDescriptor> extensions, 367 FieldDescriptor field, 368 Object value) { 369 if (builder != null) { 370 builder.addRepeatedField(field, value); 371 } else { 372 extensions.addRepeatedField(field, value); 373 } 374 } 375 376 /** helper method to handle {@code builder} and {@code extensions}. */ 377 private static void setField( 378 Message.Builder builder, 379 FieldSet<FieldDescriptor> extensions, 380 FieldDescriptor field, 381 Object value) { 382 if (builder != null) { 383 builder.setField(field, value); 384 } else { 385 extensions.setField(field, value); 386 } 387 } 388 389 /** helper method to handle {@code builder} and {@code extensions}. */ 390 private static boolean hasOriginalMessage( 391 Message.Builder builder, 392 FieldSet<FieldDescriptor> extensions, 393 FieldDescriptor field) { 394 if (builder != null) { 395 return builder.hasField(field); 396 } else { 397 return extensions.hasField(field); 398 } 399 } 400 401 /** helper method to handle {@code builder} and {@code extensions}. */ 402 private static Message getOriginalMessage( 403 Message.Builder builder, 404 FieldSet<FieldDescriptor> extensions, 405 FieldDescriptor field) { 406 if (builder != null) { 407 return (Message) builder.getField(field); 408 } else { 409 return (Message) extensions.getField(field); 410 } 411 } 412 413 /** helper method to handle {@code builder} and {@code extensions}. */ 414 private static void mergeOriginalMessage( 415 Message.Builder builder, 416 FieldSet<FieldDescriptor> extensions, 417 FieldDescriptor field, 418 Message.Builder subBuilder) { 419 Message originalMessage = getOriginalMessage(builder, extensions, field); 420 if (originalMessage != null) { 421 subBuilder.mergeFrom(originalMessage); 422 } 423 } 424 425 /** 426 * Like {@link #mergeFrom(CodedInputStream, ExtensionRegistryLite)}, but 427 * parses a single field. 428 * 429 * When {@code builder} is not null, the method will parse and merge the 430 * field into {@code builder}. Otherwise, it will try to parse the field 431 * into {@code extensions}, when it's called by the parsing constructor in 432 * generated classes. 433 * 434 * Package-private because it is used by GeneratedMessage.ExtendableMessage. 435 * @param tag The tag, which should have already been read. 436 * @return {@code true} unless the tag is an end-group tag. 437 */ 438 static boolean mergeFieldFrom( 439 CodedInputStream input, 440 UnknownFieldSet.Builder unknownFields, 441 ExtensionRegistryLite extensionRegistry, 442 Descriptor type, 443 Message.Builder builder, 444 FieldSet<FieldDescriptor> extensions, 445 int tag) throws IOException { 446 if (type.getOptions().getMessageSetWireFormat() && 447 tag == WireFormat.MESSAGE_SET_ITEM_TAG) { 448 mergeMessageSetExtensionFromCodedStream( 449 input, unknownFields, extensionRegistry, type, builder, extensions); 450 return true; 451 } 452 453 final int wireType = WireFormat.getTagWireType(tag); 454 final int fieldNumber = WireFormat.getTagFieldNumber(tag); 455 456 final FieldDescriptor field; 457 Message defaultInstance = null; 458 459 if (type.isExtensionNumber(fieldNumber)) { 460 // extensionRegistry may be either ExtensionRegistry or 461 // ExtensionRegistryLite. Since the type we are parsing is a full 462 // message, only a full ExtensionRegistry could possibly contain 463 // extensions of it. Otherwise we will treat the registry as if it 464 // were empty. 465 if (extensionRegistry instanceof ExtensionRegistry) { 466 final ExtensionRegistry.ExtensionInfo extension = 467 ((ExtensionRegistry) extensionRegistry) 468 .findExtensionByNumber(type, fieldNumber); 469 if (extension == null) { 470 field = null; 471 } else { 472 field = extension.descriptor; 473 defaultInstance = extension.defaultInstance; 474 if (defaultInstance == null && 475 field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 476 throw new IllegalStateException( 477 "Message-typed extension lacked default instance: " + 478 field.getFullName()); 479 } 480 } 481 } else { 482 field = null; 483 } 484 } else if (builder != null) { 485 field = type.findFieldByNumber(fieldNumber); 486 } else { 487 field = null; 488 } 489 490 boolean unknown = false; 491 boolean packed = false; 492 if (field == null) { 493 unknown = true; // Unknown field. 494 } else if (wireType == FieldSet.getWireFormatForFieldType( 495 field.getLiteType(), 496 false /* isPacked */)) { 497 packed = false; 498 } else if (field.isPackable() && 499 wireType == FieldSet.getWireFormatForFieldType( 500 field.getLiteType(), 501 true /* isPacked */)) { 502 packed = true; 503 } else { 504 unknown = true; // Unknown wire type. 505 } 506 507 if (unknown) { // Unknown field or wrong wire type. Skip. 508 return unknownFields.mergeFieldFrom(tag, input); 509 } 510 511 if (packed) { 512 final int length = input.readRawVarint32(); 513 final int limit = input.pushLimit(length); 514 if (field.getLiteType() == WireFormat.FieldType.ENUM) { 515 while (input.getBytesUntilLimit() > 0) { 516 final int rawValue = input.readEnum(); 517 final Object value = field.getEnumType().findValueByNumber(rawValue); 518 if (value == null) { 519 // If the number isn't recognized as a valid value for this 520 // enum, drop it (don't even add it to unknownFields). 521 return true; 522 } 523 addRepeatedField(builder, extensions, field, value); 524 } 525 } else { 526 while (input.getBytesUntilLimit() > 0) { 527 final Object value = 528 FieldSet.readPrimitiveField(input, field.getLiteType()); 529 addRepeatedField(builder, extensions, field, value); 530 } 531 } 532 input.popLimit(limit); 533 } else { 534 final Object value; 535 switch (field.getType()) { 536 case GROUP: { 537 final Message.Builder subBuilder; 538 if (defaultInstance != null) { 539 subBuilder = defaultInstance.newBuilderForType(); 540 } else { 541 subBuilder = builder.newBuilderForField(field); 542 } 543 if (!field.isRepeated()) { 544 mergeOriginalMessage(builder, extensions, field, subBuilder); 545 } 546 input.readGroup(field.getNumber(), subBuilder, extensionRegistry); 547 value = subBuilder.buildPartial(); 548 break; 549 } 550 case MESSAGE: { 551 final Message.Builder subBuilder; 552 if (defaultInstance != null) { 553 subBuilder = defaultInstance.newBuilderForType(); 554 } else { 555 subBuilder = builder.newBuilderForField(field); 556 } 557 if (!field.isRepeated()) { 558 mergeOriginalMessage(builder, extensions, field, subBuilder); 559 } 560 input.readMessage(subBuilder, extensionRegistry); 561 value = subBuilder.buildPartial(); 562 break; 563 } 564 case ENUM: 565 final int rawValue = input.readEnum(); 566 value = field.getEnumType().findValueByNumber(rawValue); 567 // If the number isn't recognized as a valid value for this enum, 568 // drop it. 569 if (value == null) { 570 unknownFields.mergeVarintField(fieldNumber, rawValue); 571 return true; 572 } 573 break; 574 default: 575 value = FieldSet.readPrimitiveField(input, field.getLiteType()); 576 break; 577 } 578 579 if (field.isRepeated()) { 580 addRepeatedField(builder, extensions, field, value); 581 } else { 582 setField(builder, extensions, field, value); 583 } 584 } 585 586 return true; 587 } 588 589 /** 590 * Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. 591 * If {@code builder} is not null, this method will merge MessageSet into 592 * the builder. Otherwise, it will merge the MessageSet into {@code 593 * extensions}. 594 */ 595 private static void mergeMessageSetExtensionFromCodedStream( 596 CodedInputStream input, 597 UnknownFieldSet.Builder unknownFields, 598 ExtensionRegistryLite extensionRegistry, 599 Descriptor type, 600 Message.Builder builder, 601 FieldSet<FieldDescriptor> extensions) throws IOException { 602 603 // The wire format for MessageSet is: 604 // message MessageSet { 605 // repeated group Item = 1 { 606 // required int32 typeId = 2; 607 // required bytes message = 3; 608 // } 609 // } 610 // "typeId" is the extension's field number. The extension can only be 611 // a message type, where "message" contains the encoded bytes of that 612 // message. 613 // 614 // In practice, we will probably never see a MessageSet item in which 615 // the message appears before the type ID, or where either field does not 616 // appear exactly once. However, in theory such cases are valid, so we 617 // should be prepared to accept them. 618 619 int typeId = 0; 620 ByteString rawBytes = null; // If we encounter "message" before "typeId" 621 ExtensionRegistry.ExtensionInfo extension = null; 622 623 // Read bytes from input, if we get it's type first then parse it eagerly, 624 // otherwise we store the raw bytes in a local variable. 625 while (true) { 626 final int tag = input.readTag(); 627 if (tag == 0) { 628 break; 629 } 630 631 if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { 632 typeId = input.readUInt32(); 633 if (typeId != 0) { 634 // extensionRegistry may be either ExtensionRegistry or 635 // ExtensionRegistryLite. Since the type we are parsing is a full 636 // message, only a full ExtensionRegistry could possibly contain 637 // extensions of it. Otherwise we will treat the registry as if it 638 // were empty. 639 if (extensionRegistry instanceof ExtensionRegistry) { 640 extension = ((ExtensionRegistry) extensionRegistry) 641 .findExtensionByNumber(type, typeId); 642 } 643 } 644 645 } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { 646 if (typeId != 0) { 647 if (extension != null && ExtensionRegistryLite.isEagerlyParseMessageSets()) { 648 // We already know the type, so we can parse directly from the 649 // input with no copying. Hooray! 650 eagerlyMergeMessageSetExtension( 651 input, extension, extensionRegistry, builder, extensions); 652 rawBytes = null; 653 continue; 654 } 655 } 656 // We haven't seen a type ID yet or we want parse message lazily. 657 rawBytes = input.readBytes(); 658 659 } else { // Unknown tag. Skip it. 660 if (!input.skipField(tag)) { 661 break; // End of group 662 } 663 } 664 } 665 input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); 666 667 // Process the raw bytes. 668 if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID. 669 if (extension != null) { // We known the type 670 mergeMessageSetExtensionFromBytes( 671 rawBytes, extension, extensionRegistry, builder, extensions); 672 } else { // We don't know how to parse this. Ignore it. 673 if (rawBytes != null) { 674 unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder() 675 .addLengthDelimited(rawBytes).build()); 676 } 677 } 678 } 679 } 680 681 private static void eagerlyMergeMessageSetExtension( 682 CodedInputStream input, 683 ExtensionRegistry.ExtensionInfo extension, 684 ExtensionRegistryLite extensionRegistry, 685 Message.Builder builder, 686 FieldSet<FieldDescriptor> extensions) throws IOException { 687 688 FieldDescriptor field = extension.descriptor; 689 Message value = null; 690 if (hasOriginalMessage(builder, extensions, field)) { 691 Message originalMessage = 692 getOriginalMessage(builder, extensions, field); 693 Message.Builder subBuilder = originalMessage.toBuilder(); 694 input.readMessage(subBuilder, extensionRegistry); 695 value = subBuilder.buildPartial(); 696 } else { 697 value = input.readMessage(extension.defaultInstance.getParserForType(), 698 extensionRegistry); 699 } 700 701 if (builder != null) { 702 builder.setField(field, value); 703 } else { 704 extensions.setField(field, value); 705 } 706 } 707 708 private static void mergeMessageSetExtensionFromBytes( 709 ByteString rawBytes, 710 ExtensionRegistry.ExtensionInfo extension, 711 ExtensionRegistryLite extensionRegistry, 712 Message.Builder builder, 713 FieldSet<FieldDescriptor> extensions) throws IOException { 714 715 FieldDescriptor field = extension.descriptor; 716 boolean hasOriginalValue = hasOriginalMessage(builder, extensions, field); 717 718 if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) { 719 // If the field already exists, we just parse the field. 720 Message value = null; 721 if (hasOriginalValue) { 722 Message originalMessage = 723 getOriginalMessage(builder, extensions, field); 724 Message.Builder subBuilder= originalMessage.toBuilder(); 725 subBuilder.mergeFrom(rawBytes, extensionRegistry); 726 value = subBuilder.buildPartial(); 727 } else { 728 value = extension.defaultInstance.getParserForType() 729 .parsePartialFrom(rawBytes, extensionRegistry); 730 } 731 setField(builder, extensions, field, value); 732 } else { 733 // Use LazyField to load MessageSet lazily. 734 LazyField lazyField = new LazyField( 735 extension.defaultInstance, extensionRegistry, rawBytes); 736 if (builder != null) { 737 // TODO(xiangl): it looks like this method can only be invoked by 738 // ExtendableBuilder, but I'm not sure. So I double check the type of 739 // builder here. It may be useless and need more investigation. 740 if (builder instanceof ExtendableBuilder) { 741 builder.setField(field, lazyField); 742 } else { 743 builder.setField(field, lazyField.getValue()); 744 } 745 } else { 746 extensions.setField(field, lazyField); 747 } 748 } 749 } 750 751 public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { 752 setUnknownFields( 753 UnknownFieldSet.newBuilder(getUnknownFields()) 754 .mergeFrom(unknownFields) 755 .build()); 756 return (BuilderType) this; 757 } 758 759 public Message.Builder getFieldBuilder(final FieldDescriptor field) { 760 throw new UnsupportedOperationException( 761 "getFieldBuilder() called on an unsupported message type."); 762 } 763 764 /** 765 * Construct an UninitializedMessageException reporting missing fields in 766 * the given message. 767 */ 768 protected static UninitializedMessageException 769 newUninitializedMessageException(Message message) { 770 return new UninitializedMessageException(findMissingFields(message)); 771 } 772 773 /** 774 * Populates {@code this.missingFields} with the full "path" of each 775 * missing required field in the given message. 776 */ 777 private static List<String> findMissingFields( 778 final MessageOrBuilder message) { 779 final List<String> results = new ArrayList<String>(); 780 findMissingFields(message, "", results); 781 return results; 782 } 783 784 /** Recursive helper implementing {@link #findMissingFields(Message)}. */ 785 private static void findMissingFields(final MessageOrBuilder message, 786 final String prefix, 787 final List<String> results) { 788 for (final FieldDescriptor field : 789 message.getDescriptorForType().getFields()) { 790 if (field.isRequired() && !message.hasField(field)) { 791 results.add(prefix + field.getName()); 792 } 793 } 794 795 for (final Map.Entry<FieldDescriptor, Object> entry : 796 message.getAllFields().entrySet()) { 797 final FieldDescriptor field = entry.getKey(); 798 final Object value = entry.getValue(); 799 800 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 801 if (field.isRepeated()) { 802 int i = 0; 803 for (final Object element : (List) value) { 804 findMissingFields((MessageOrBuilder) element, 805 subMessagePrefix(prefix, field, i++), 806 results); 807 } 808 } else { 809 if (message.hasField(field)) { 810 findMissingFields((MessageOrBuilder) value, 811 subMessagePrefix(prefix, field, -1), 812 results); 813 } 814 } 815 } 816 } 817 } 818 819 private static String subMessagePrefix(final String prefix, 820 final FieldDescriptor field, 821 final int index) { 822 final StringBuilder result = new StringBuilder(prefix); 823 if (field.isExtension()) { 824 result.append('(') 825 .append(field.getFullName()) 826 .append(')'); 827 } else { 828 result.append(field.getName()); 829 } 830 if (index != -1) { 831 result.append('[') 832 .append(index) 833 .append(']'); 834 } 835 result.append('.'); 836 return result.toString(); 837 } 838 839 // =============================================================== 840 // The following definitions seem to be required in order to make javac 841 // not produce weird errors like: 842 // 843 // java/com/google/protobuf/DynamicMessage.java:203: types 844 // com.google.protobuf.AbstractMessage.Builder< 845 // com.google.protobuf.DynamicMessage.Builder> and 846 // com.google.protobuf.AbstractMessage.Builder< 847 // com.google.protobuf.DynamicMessage.Builder> are incompatible; both 848 // define mergeFrom(com.google.protobuf.ByteString), but with unrelated 849 // return types. 850 // 851 // Strangely, these lines are only needed if javac is invoked separately 852 // on AbstractMessage.java and AbstractMessageLite.java. If javac is 853 // invoked on both simultaneously, it works. (Or maybe the important 854 // point is whether or not DynamicMessage.java is compiled together with 855 // AbstractMessageLite.java -- not sure.) I suspect this is a compiler 856 // bug. 857 858 @Override 859 public BuilderType mergeFrom(final ByteString data) 860 throws InvalidProtocolBufferException { 861 return super.mergeFrom(data); 862 } 863 864 @Override 865 public BuilderType mergeFrom( 866 final ByteString data, 867 final ExtensionRegistryLite extensionRegistry) 868 throws InvalidProtocolBufferException { 869 return super.mergeFrom(data, extensionRegistry); 870 } 871 872 @Override 873 public BuilderType mergeFrom(final byte[] data) 874 throws InvalidProtocolBufferException { 875 return super.mergeFrom(data); 876 } 877 878 @Override 879 public BuilderType mergeFrom( 880 final byte[] data, final int off, final int len) 881 throws InvalidProtocolBufferException { 882 return super.mergeFrom(data, off, len); 883 } 884 885 @Override 886 public BuilderType mergeFrom( 887 final byte[] data, 888 final ExtensionRegistryLite extensionRegistry) 889 throws InvalidProtocolBufferException { 890 return super.mergeFrom(data, extensionRegistry); 891 } 892 893 @Override 894 public BuilderType mergeFrom( 895 final byte[] data, final int off, final int len, 896 final ExtensionRegistryLite extensionRegistry) 897 throws InvalidProtocolBufferException { 898 return super.mergeFrom(data, off, len, extensionRegistry); 899 } 900 901 @Override 902 public BuilderType mergeFrom(final InputStream input) 903 throws IOException { 904 return super.mergeFrom(input); 905 } 906 907 @Override 908 public BuilderType mergeFrom( 909 final InputStream input, 910 final ExtensionRegistryLite extensionRegistry) 911 throws IOException { 912 return super.mergeFrom(input, extensionRegistry); 913 } 914 915 @Override 916 public boolean mergeDelimitedFrom(final InputStream input) 917 throws IOException { 918 return super.mergeDelimitedFrom(input); 919 } 920 921 @Override 922 public boolean mergeDelimitedFrom( 923 final InputStream input, 924 final ExtensionRegistryLite extensionRegistry) 925 throws IOException { 926 return super.mergeDelimitedFrom(input, extensionRegistry); 927 } 928 929 } 930 } 931