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 36 import java.io.InputStream; 37 import java.io.IOException; 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Map; 41 42 /** 43 * A partial implementation of the {@link Message} interface which implements 44 * as many methods of that interface as possible in terms of other methods. 45 * 46 * @author kenton (at) google.com Kenton Varda 47 */ 48 public abstract class AbstractMessage extends AbstractMessageLite 49 implements Message { 50 @SuppressWarnings("unchecked") 51 public boolean isInitialized() { 52 // Check that all required fields are present. 53 for (final FieldDescriptor field : getDescriptorForType().getFields()) { 54 if (field.isRequired()) { 55 if (!hasField(field)) { 56 return false; 57 } 58 } 59 } 60 61 // Check that embedded messages are initialized. 62 for (final Map.Entry<FieldDescriptor, Object> entry : 63 getAllFields().entrySet()) { 64 final FieldDescriptor field = entry.getKey(); 65 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 66 if (field.isRepeated()) { 67 for (final Message element : (List<Message>) entry.getValue()) { 68 if (!element.isInitialized()) { 69 return false; 70 } 71 } 72 } else { 73 if (!((Message) entry.getValue()).isInitialized()) { 74 return false; 75 } 76 } 77 } 78 } 79 80 return true; 81 } 82 83 @Override 84 public final String toString() { 85 return TextFormat.printToString(this); 86 } 87 88 public void writeTo(final CodedOutputStream output) throws IOException { 89 final boolean isMessageSet = 90 getDescriptorForType().getOptions().getMessageSetWireFormat(); 91 92 for (final Map.Entry<FieldDescriptor, Object> entry : 93 getAllFields().entrySet()) { 94 final FieldDescriptor field = entry.getKey(); 95 final Object value = entry.getValue(); 96 if (isMessageSet && field.isExtension() && 97 field.getType() == FieldDescriptor.Type.MESSAGE && 98 !field.isRepeated()) { 99 output.writeMessageSetExtension(field.getNumber(), (Message) value); 100 } else { 101 FieldSet.writeField(field, value, output); 102 } 103 } 104 105 final UnknownFieldSet unknownFields = getUnknownFields(); 106 if (isMessageSet) { 107 unknownFields.writeAsMessageSetTo(output); 108 } else { 109 unknownFields.writeTo(output); 110 } 111 } 112 113 private int memoizedSize = -1; 114 115 public int getSerializedSize() { 116 int size = memoizedSize; 117 if (size != -1) { 118 return size; 119 } 120 121 size = 0; 122 final boolean isMessageSet = 123 getDescriptorForType().getOptions().getMessageSetWireFormat(); 124 125 for (final Map.Entry<FieldDescriptor, Object> entry : 126 getAllFields().entrySet()) { 127 final FieldDescriptor field = entry.getKey(); 128 final Object value = entry.getValue(); 129 if (isMessageSet && field.isExtension() && 130 field.getType() == FieldDescriptor.Type.MESSAGE && 131 !field.isRepeated()) { 132 size += CodedOutputStream.computeMessageSetExtensionSize( 133 field.getNumber(), (Message) value); 134 } else { 135 size += FieldSet.computeFieldSize(field, value); 136 } 137 } 138 139 final UnknownFieldSet unknownFields = getUnknownFields(); 140 if (isMessageSet) { 141 size += unknownFields.getSerializedSizeAsMessageSet(); 142 } else { 143 size += unknownFields.getSerializedSize(); 144 } 145 146 memoizedSize = size; 147 return size; 148 } 149 150 @Override 151 public boolean equals(final Object other) { 152 if (other == this) { 153 return true; 154 } 155 if (!(other instanceof Message)) { 156 return false; 157 } 158 final Message otherMessage = (Message) other; 159 if (getDescriptorForType() != otherMessage.getDescriptorForType()) { 160 return false; 161 } 162 return getAllFields().equals(otherMessage.getAllFields()) && 163 getUnknownFields().equals(otherMessage.getUnknownFields()); 164 } 165 166 @Override 167 public int hashCode() { 168 int hash = 41; 169 hash = (19 * hash) + getDescriptorForType().hashCode(); 170 hash = (53 * hash) + getAllFields().hashCode(); 171 hash = (29 * hash) + getUnknownFields().hashCode(); 172 return hash; 173 } 174 175 // ================================================================= 176 177 /** 178 * A partial implementation of the {@link Message.Builder} interface which 179 * implements as many methods of that interface as possible in terms of 180 * other methods. 181 */ 182 @SuppressWarnings("unchecked") 183 public static abstract class Builder<BuilderType extends Builder> 184 extends AbstractMessageLite.Builder<BuilderType> 185 implements Message.Builder { 186 // The compiler produces an error if this is not declared explicitly. 187 @Override 188 public abstract BuilderType clone(); 189 190 public BuilderType clear() { 191 for (final Map.Entry<FieldDescriptor, Object> entry : 192 getAllFields().entrySet()) { 193 clearField(entry.getKey()); 194 } 195 return (BuilderType) this; 196 } 197 198 public BuilderType mergeFrom(final Message other) { 199 if (other.getDescriptorForType() != getDescriptorForType()) { 200 throw new IllegalArgumentException( 201 "mergeFrom(Message) can only merge messages of the same type."); 202 } 203 204 // Note: We don't attempt to verify that other's fields have valid 205 // types. Doing so would be a losing battle. We'd have to verify 206 // all sub-messages as well, and we'd have to make copies of all of 207 // them to insure that they don't change after verification (since 208 // the Message interface itself cannot enforce immutability of 209 // implementations). 210 // TODO(kenton): Provide a function somewhere called makeDeepCopy() 211 // which allows people to make secure deep copies of messages. 212 213 for (final Map.Entry<FieldDescriptor, Object> entry : 214 other.getAllFields().entrySet()) { 215 final FieldDescriptor field = entry.getKey(); 216 if (field.isRepeated()) { 217 for (final Object element : (List)entry.getValue()) { 218 addRepeatedField(field, element); 219 } 220 } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 221 final Message existingValue = (Message)getField(field); 222 if (existingValue == existingValue.getDefaultInstanceForType()) { 223 setField(field, entry.getValue()); 224 } else { 225 setField(field, 226 existingValue.newBuilderForType() 227 .mergeFrom(existingValue) 228 .mergeFrom((Message)entry.getValue()) 229 .build()); 230 } 231 } else { 232 setField(field, entry.getValue()); 233 } 234 } 235 236 mergeUnknownFields(other.getUnknownFields()); 237 238 return (BuilderType) this; 239 } 240 241 @Override 242 public BuilderType mergeFrom(final CodedInputStream input) 243 throws IOException { 244 return mergeFrom(input, ExtensionRegistry.getEmptyRegistry()); 245 } 246 247 @Override 248 public BuilderType mergeFrom( 249 final CodedInputStream input, 250 final ExtensionRegistryLite extensionRegistry) 251 throws IOException { 252 final UnknownFieldSet.Builder unknownFields = 253 UnknownFieldSet.newBuilder(getUnknownFields()); 254 while (true) { 255 final int tag = input.readTag(); 256 if (tag == 0) { 257 break; 258 } 259 260 if (!mergeFieldFrom(input, unknownFields, extensionRegistry, 261 this, tag)) { 262 // end group tag 263 break; 264 } 265 } 266 setUnknownFields(unknownFields.build()); 267 return (BuilderType) this; 268 } 269 270 /** 271 * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder, 272 * ExtensionRegistryLite, Message.Builder)}, but parses a single field. 273 * Package-private because it is used by GeneratedMessage.ExtendableMessage. 274 * @param tag The tag, which should have already been read. 275 * @return {@code true} unless the tag is an end-group tag. 276 */ 277 @SuppressWarnings("unchecked") 278 static boolean mergeFieldFrom( 279 final CodedInputStream input, 280 final UnknownFieldSet.Builder unknownFields, 281 final ExtensionRegistryLite extensionRegistry, 282 final Message.Builder builder, 283 final int tag) throws IOException { 284 final Descriptor type = builder.getDescriptorForType(); 285 286 if (type.getOptions().getMessageSetWireFormat() && 287 tag == WireFormat.MESSAGE_SET_ITEM_TAG) { 288 mergeMessageSetExtensionFromCodedStream( 289 input, unknownFields, extensionRegistry, builder); 290 return true; 291 } 292 293 final int wireType = WireFormat.getTagWireType(tag); 294 final int fieldNumber = WireFormat.getTagFieldNumber(tag); 295 296 final FieldDescriptor field; 297 Message defaultInstance = null; 298 299 if (type.isExtensionNumber(fieldNumber)) { 300 // extensionRegistry may be either ExtensionRegistry or 301 // ExtensionRegistryLite. Since the type we are parsing is a full 302 // message, only a full ExtensionRegistry could possibly contain 303 // extensions of it. Otherwise we will treat the registry as if it 304 // were empty. 305 if (extensionRegistry instanceof ExtensionRegistry) { 306 final ExtensionRegistry.ExtensionInfo extension = 307 ((ExtensionRegistry) extensionRegistry) 308 .findExtensionByNumber(type, fieldNumber); 309 if (extension == null) { 310 field = null; 311 } else { 312 field = extension.descriptor; 313 defaultInstance = extension.defaultInstance; 314 if (defaultInstance == null && 315 field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 316 throw new IllegalStateException( 317 "Message-typed extension lacked default instance: " + 318 field.getFullName()); 319 } 320 } 321 } else { 322 field = null; 323 } 324 } else { 325 field = type.findFieldByNumber(fieldNumber); 326 } 327 328 boolean unknown = false; 329 boolean packed = false; 330 if (field == null) { 331 unknown = true; // Unknown field. 332 } else if (wireType == FieldSet.getWireFormatForFieldType( 333 field.getLiteType(), 334 false /* isPacked */)) { 335 packed = false; 336 } else if (field.isPackable() && 337 wireType == FieldSet.getWireFormatForFieldType( 338 field.getLiteType(), 339 true /* isPacked */)) { 340 packed = true; 341 } else { 342 unknown = true; // Unknown wire type. 343 } 344 345 if (unknown) { // Unknown field or wrong wire type. Skip. 346 return unknownFields.mergeFieldFrom(tag, input); 347 } 348 349 if (packed) { 350 final int length = input.readRawVarint32(); 351 final int limit = input.pushLimit(length); 352 if (field.getLiteType() == WireFormat.FieldType.ENUM) { 353 while (input.getBytesUntilLimit() > 0) { 354 final int rawValue = input.readEnum(); 355 final Object value = field.getEnumType().findValueByNumber(rawValue); 356 if (value == null) { 357 // If the number isn't recognized as a valid value for this 358 // enum, drop it (don't even add it to unknownFields). 359 return true; 360 } 361 builder.addRepeatedField(field, value); 362 } 363 } else { 364 while (input.getBytesUntilLimit() > 0) { 365 final Object value = 366 FieldSet.readPrimitiveField(input, field.getLiteType()); 367 builder.addRepeatedField(field, value); 368 } 369 } 370 input.popLimit(limit); 371 } else { 372 final Object value; 373 switch (field.getType()) { 374 case GROUP: { 375 final Message.Builder subBuilder; 376 if (defaultInstance != null) { 377 subBuilder = defaultInstance.newBuilderForType(); 378 } else { 379 subBuilder = builder.newBuilderForField(field); 380 } 381 if (!field.isRepeated()) { 382 subBuilder.mergeFrom((Message) builder.getField(field)); 383 } 384 input.readGroup(field.getNumber(), subBuilder, extensionRegistry); 385 value = subBuilder.build(); 386 break; 387 } 388 case MESSAGE: { 389 final Message.Builder subBuilder; 390 if (defaultInstance != null) { 391 subBuilder = defaultInstance.newBuilderForType(); 392 } else { 393 subBuilder = builder.newBuilderForField(field); 394 } 395 if (!field.isRepeated()) { 396 subBuilder.mergeFrom((Message) builder.getField(field)); 397 } 398 input.readMessage(subBuilder, extensionRegistry); 399 value = subBuilder.build(); 400 break; 401 } 402 case ENUM: 403 final int rawValue = input.readEnum(); 404 value = field.getEnumType().findValueByNumber(rawValue); 405 // If the number isn't recognized as a valid value for this enum, 406 // drop it. 407 if (value == null) { 408 unknownFields.mergeVarintField(fieldNumber, rawValue); 409 return true; 410 } 411 break; 412 default: 413 value = FieldSet.readPrimitiveField(input, field.getLiteType()); 414 break; 415 } 416 417 if (field.isRepeated()) { 418 builder.addRepeatedField(field, value); 419 } else { 420 builder.setField(field, value); 421 } 422 } 423 424 return true; 425 } 426 427 /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */ 428 private static void mergeMessageSetExtensionFromCodedStream( 429 final CodedInputStream input, 430 final UnknownFieldSet.Builder unknownFields, 431 final ExtensionRegistryLite extensionRegistry, 432 final Message.Builder builder) throws IOException { 433 final Descriptor type = builder.getDescriptorForType(); 434 435 // The wire format for MessageSet is: 436 // message MessageSet { 437 // repeated group Item = 1 { 438 // required int32 typeId = 2; 439 // required bytes message = 3; 440 // } 441 // } 442 // "typeId" is the extension's field number. The extension can only be 443 // a message type, where "message" contains the encoded bytes of that 444 // message. 445 // 446 // In practice, we will probably never see a MessageSet item in which 447 // the message appears before the type ID, or where either field does not 448 // appear exactly once. However, in theory such cases are valid, so we 449 // should be prepared to accept them. 450 451 int typeId = 0; 452 ByteString rawBytes = null; // If we encounter "message" before "typeId" 453 Message.Builder subBuilder = null; 454 FieldDescriptor field = null; 455 456 while (true) { 457 final int tag = input.readTag(); 458 if (tag == 0) { 459 break; 460 } 461 462 if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { 463 typeId = input.readUInt32(); 464 // Zero is not a valid type ID. 465 if (typeId != 0) { 466 final ExtensionRegistry.ExtensionInfo extension; 467 468 // extensionRegistry may be either ExtensionRegistry or 469 // ExtensionRegistryLite. Since the type we are parsing is a full 470 // message, only a full ExtensionRegistry could possibly contain 471 // extensions of it. Otherwise we will treat the registry as if it 472 // were empty. 473 if (extensionRegistry instanceof ExtensionRegistry) { 474 extension = ((ExtensionRegistry) extensionRegistry) 475 .findExtensionByNumber(type, typeId); 476 } else { 477 extension = null; 478 } 479 480 if (extension != null) { 481 field = extension.descriptor; 482 subBuilder = extension.defaultInstance.newBuilderForType(); 483 final Message originalMessage = (Message)builder.getField(field); 484 if (originalMessage != null) { 485 subBuilder.mergeFrom(originalMessage); 486 } 487 if (rawBytes != null) { 488 // We already encountered the message. Parse it now. 489 subBuilder.mergeFrom( 490 CodedInputStream.newInstance(rawBytes.newInput())); 491 rawBytes = null; 492 } 493 } else { 494 // Unknown extension number. If we already saw data, put it 495 // in rawBytes. 496 if (rawBytes != null) { 497 unknownFields.mergeField(typeId, 498 UnknownFieldSet.Field.newBuilder() 499 .addLengthDelimited(rawBytes) 500 .build()); 501 rawBytes = null; 502 } 503 } 504 } 505 } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { 506 if (typeId == 0) { 507 // We haven't seen a type ID yet, so we have to store the raw bytes 508 // for now. 509 rawBytes = input.readBytes(); 510 } else if (subBuilder == null) { 511 // We don't know how to parse this. Ignore it. 512 unknownFields.mergeField(typeId, 513 UnknownFieldSet.Field.newBuilder() 514 .addLengthDelimited(input.readBytes()) 515 .build()); 516 } else { 517 // We already know the type, so we can parse directly from the input 518 // with no copying. Hooray! 519 input.readMessage(subBuilder, extensionRegistry); 520 } 521 } else { 522 // Unknown tag. Skip it. 523 if (!input.skipField(tag)) { 524 break; // end of group 525 } 526 } 527 } 528 529 input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); 530 531 if (subBuilder != null) { 532 builder.setField(field, subBuilder.build()); 533 } 534 } 535 536 public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { 537 setUnknownFields( 538 UnknownFieldSet.newBuilder(getUnknownFields()) 539 .mergeFrom(unknownFields) 540 .build()); 541 return (BuilderType) this; 542 } 543 544 /** 545 * Construct an UninitializedMessageException reporting missing fields in 546 * the given message. 547 */ 548 protected static UninitializedMessageException 549 newUninitializedMessageException(Message message) { 550 return new UninitializedMessageException(findMissingFields(message)); 551 } 552 553 /** 554 * Populates {@code this.missingFields} with the full "path" of each 555 * missing required field in the given message. 556 */ 557 private static List<String> findMissingFields(final Message message) { 558 final List<String> results = new ArrayList<String>(); 559 findMissingFields(message, "", results); 560 return results; 561 } 562 563 /** Recursive helper implementing {@link #findMissingFields(Message)}. */ 564 private static void findMissingFields(final Message message, 565 final String prefix, 566 final List<String> results) { 567 for (final FieldDescriptor field : 568 message.getDescriptorForType().getFields()) { 569 if (field.isRequired() && !message.hasField(field)) { 570 results.add(prefix + field.getName()); 571 } 572 } 573 574 for (final Map.Entry<FieldDescriptor, Object> entry : 575 message.getAllFields().entrySet()) { 576 final FieldDescriptor field = entry.getKey(); 577 final Object value = entry.getValue(); 578 579 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 580 if (field.isRepeated()) { 581 int i = 0; 582 for (final Object element : (List) value) { 583 findMissingFields((Message) element, 584 subMessagePrefix(prefix, field, i++), 585 results); 586 } 587 } else { 588 if (message.hasField(field)) { 589 findMissingFields((Message) value, 590 subMessagePrefix(prefix, field, -1), 591 results); 592 } 593 } 594 } 595 } 596 } 597 598 private static String subMessagePrefix(final String prefix, 599 final FieldDescriptor field, 600 final int index) { 601 final StringBuilder result = new StringBuilder(prefix); 602 if (field.isExtension()) { 603 result.append('(') 604 .append(field.getFullName()) 605 .append(')'); 606 } else { 607 result.append(field.getName()); 608 } 609 if (index != -1) { 610 result.append('[') 611 .append(index) 612 .append(']'); 613 } 614 result.append('.'); 615 return result.toString(); 616 } 617 618 // =============================================================== 619 // The following definitions seem to be required in order to make javac 620 // not produce weird errors like: 621 // 622 // java/com/google/protobuf/DynamicMessage.java:203: types 623 // com.google.protobuf.AbstractMessage.Builder< 624 // com.google.protobuf.DynamicMessage.Builder> and 625 // com.google.protobuf.AbstractMessage.Builder< 626 // com.google.protobuf.DynamicMessage.Builder> are incompatible; both 627 // define mergeFrom(com.google.protobuf.ByteString), but with unrelated 628 // return types. 629 // 630 // Strangely, these lines are only needed if javac is invoked separately 631 // on AbstractMessage.java and AbstractMessageLite.java. If javac is 632 // invoked on both simultaneously, it works. (Or maybe the important 633 // point is whether or not DynamicMessage.java is compiled together with 634 // AbstractMessageLite.java -- not sure.) I suspect this is a compiler 635 // bug. 636 637 @Override 638 public BuilderType mergeFrom(final ByteString data) 639 throws InvalidProtocolBufferException { 640 return super.mergeFrom(data); 641 } 642 643 @Override 644 public BuilderType mergeFrom( 645 final ByteString data, 646 final ExtensionRegistryLite extensionRegistry) 647 throws InvalidProtocolBufferException { 648 return super.mergeFrom(data, extensionRegistry); 649 } 650 651 @Override 652 public BuilderType mergeFrom(final byte[] data) 653 throws InvalidProtocolBufferException { 654 return super.mergeFrom(data); 655 } 656 657 @Override 658 public BuilderType mergeFrom( 659 final byte[] data, final int off, final int len) 660 throws InvalidProtocolBufferException { 661 return super.mergeFrom(data, off, len); 662 } 663 664 @Override 665 public BuilderType mergeFrom( 666 final byte[] data, 667 final ExtensionRegistryLite extensionRegistry) 668 throws InvalidProtocolBufferException { 669 return super.mergeFrom(data, extensionRegistry); 670 } 671 672 @Override 673 public BuilderType mergeFrom( 674 final byte[] data, final int off, final int len, 675 final ExtensionRegistryLite extensionRegistry) 676 throws InvalidProtocolBufferException { 677 return super.mergeFrom(data, off, len, extensionRegistry); 678 } 679 680 @Override 681 public BuilderType mergeFrom(final InputStream input) 682 throws IOException { 683 return super.mergeFrom(input); 684 } 685 686 @Override 687 public BuilderType mergeFrom( 688 final InputStream input, 689 final ExtensionRegistryLite extensionRegistry) 690 throws IOException { 691 return super.mergeFrom(input, extensionRegistry); 692 } 693 694 @Override 695 public boolean mergeDelimitedFrom(final InputStream input) 696 throws IOException { 697 return super.mergeDelimitedFrom(input); 698 } 699 700 @Override 701 public boolean mergeDelimitedFrom( 702 final InputStream input, 703 final ExtensionRegistryLite extensionRegistry) 704 throws IOException { 705 return super.mergeDelimitedFrom(input, extensionRegistry); 706 } 707 708 } 709 } 710