AbstractMessage.java revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
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 31package com.google.protobuf; 32 33import com.google.protobuf.Descriptors.Descriptor; 34import com.google.protobuf.Descriptors.FieldDescriptor; 35 36import java.io.InputStream; 37import java.io.IOException; 38import java.util.ArrayList; 39import java.util.List; 40import 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@google.com Kenton Varda 47 */ 48public 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 } 315 } else { 316 field = null; 317 } 318 } else { 319 field = type.findFieldByNumber(fieldNumber); 320 } 321 322 if (field == null || wireType != 323 FieldSet.getWireFormatForFieldType( 324 field.getLiteType(), 325 field.getOptions().getPacked())) { 326 // Unknown field or wrong wire type. Skip. 327 return unknownFields.mergeFieldFrom(tag, input); 328 } 329 330 if (field.getOptions().getPacked()) { 331 final int length = input.readRawVarint32(); 332 final int limit = input.pushLimit(length); 333 if (field.getLiteType() == WireFormat.FieldType.ENUM) { 334 while (input.getBytesUntilLimit() > 0) { 335 final int rawValue = input.readEnum(); 336 final Object value = field.getEnumType().findValueByNumber(rawValue); 337 if (value == null) { 338 // If the number isn't recognized as a valid value for this 339 // enum, drop it (don't even add it to unknownFields). 340 return true; 341 } 342 builder.addRepeatedField(field, value); 343 } 344 } else { 345 while (input.getBytesUntilLimit() > 0) { 346 final Object value = 347 FieldSet.readPrimitiveField(input, field.getLiteType()); 348 builder.addRepeatedField(field, value); 349 } 350 } 351 input.popLimit(limit); 352 } else { 353 final Object value; 354 switch (field.getType()) { 355 case GROUP: { 356 final Message.Builder subBuilder; 357 if (defaultInstance != null) { 358 subBuilder = defaultInstance.newBuilderForType(); 359 } else { 360 subBuilder = builder.newBuilderForField(field); 361 } 362 if (!field.isRepeated()) { 363 subBuilder.mergeFrom((Message) builder.getField(field)); 364 } 365 input.readGroup(field.getNumber(), subBuilder, extensionRegistry); 366 value = subBuilder.build(); 367 break; 368 } 369 case MESSAGE: { 370 final Message.Builder subBuilder; 371 if (defaultInstance != null) { 372 subBuilder = defaultInstance.newBuilderForType(); 373 } else { 374 subBuilder = builder.newBuilderForField(field); 375 } 376 if (!field.isRepeated()) { 377 subBuilder.mergeFrom((Message) builder.getField(field)); 378 } 379 input.readMessage(subBuilder, extensionRegistry); 380 value = subBuilder.build(); 381 break; 382 } 383 case ENUM: 384 final int rawValue = input.readEnum(); 385 value = field.getEnumType().findValueByNumber(rawValue); 386 // If the number isn't recognized as a valid value for this enum, 387 // drop it. 388 if (value == null) { 389 unknownFields.mergeVarintField(fieldNumber, rawValue); 390 return true; 391 } 392 break; 393 default: 394 value = FieldSet.readPrimitiveField(input, field.getLiteType()); 395 break; 396 } 397 398 if (field.isRepeated()) { 399 builder.addRepeatedField(field, value); 400 } else { 401 builder.setField(field, value); 402 } 403 } 404 405 return true; 406 } 407 408 /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */ 409 private static void mergeMessageSetExtensionFromCodedStream( 410 final CodedInputStream input, 411 final UnknownFieldSet.Builder unknownFields, 412 final ExtensionRegistryLite extensionRegistry, 413 final Message.Builder builder) throws IOException { 414 final Descriptor type = builder.getDescriptorForType(); 415 416 // The wire format for MessageSet is: 417 // message MessageSet { 418 // repeated group Item = 1 { 419 // required int32 typeId = 2; 420 // required bytes message = 3; 421 // } 422 // } 423 // "typeId" is the extension's field number. The extension can only be 424 // a message type, where "message" contains the encoded bytes of that 425 // message. 426 // 427 // In practice, we will probably never see a MessageSet item in which 428 // the message appears before the type ID, or where either field does not 429 // appear exactly once. However, in theory such cases are valid, so we 430 // should be prepared to accept them. 431 432 int typeId = 0; 433 ByteString rawBytes = null; // If we encounter "message" before "typeId" 434 Message.Builder subBuilder = null; 435 FieldDescriptor field = null; 436 437 while (true) { 438 final int tag = input.readTag(); 439 if (tag == 0) { 440 break; 441 } 442 443 if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) { 444 typeId = input.readUInt32(); 445 // Zero is not a valid type ID. 446 if (typeId != 0) { 447 final ExtensionRegistry.ExtensionInfo extension; 448 449 // extensionRegistry may be either ExtensionRegistry or 450 // ExtensionRegistryLite. Since the type we are parsing is a full 451 // message, only a full ExtensionRegistry could possibly contain 452 // extensions of it. Otherwise we will treat the registry as if it 453 // were empty. 454 if (extensionRegistry instanceof ExtensionRegistry) { 455 extension = ((ExtensionRegistry) extensionRegistry) 456 .findExtensionByNumber(type, typeId); 457 } else { 458 extension = null; 459 } 460 461 if (extension != null) { 462 field = extension.descriptor; 463 subBuilder = extension.defaultInstance.newBuilderForType(); 464 final Message originalMessage = (Message)builder.getField(field); 465 if (originalMessage != null) { 466 subBuilder.mergeFrom(originalMessage); 467 } 468 if (rawBytes != null) { 469 // We already encountered the message. Parse it now. 470 subBuilder.mergeFrom( 471 CodedInputStream.newInstance(rawBytes.newInput())); 472 rawBytes = null; 473 } 474 } else { 475 // Unknown extension number. If we already saw data, put it 476 // in rawBytes. 477 if (rawBytes != null) { 478 unknownFields.mergeField(typeId, 479 UnknownFieldSet.Field.newBuilder() 480 .addLengthDelimited(rawBytes) 481 .build()); 482 rawBytes = null; 483 } 484 } 485 } 486 } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) { 487 if (typeId == 0) { 488 // We haven't seen a type ID yet, so we have to store the raw bytes 489 // for now. 490 rawBytes = input.readBytes(); 491 } else if (subBuilder == null) { 492 // We don't know how to parse this. Ignore it. 493 unknownFields.mergeField(typeId, 494 UnknownFieldSet.Field.newBuilder() 495 .addLengthDelimited(input.readBytes()) 496 .build()); 497 } else { 498 // We already know the type, so we can parse directly from the input 499 // with no copying. Hooray! 500 input.readMessage(subBuilder, extensionRegistry); 501 } 502 } else { 503 // Unknown tag. Skip it. 504 if (!input.skipField(tag)) { 505 break; // end of group 506 } 507 } 508 } 509 510 input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG); 511 512 if (subBuilder != null) { 513 builder.setField(field, subBuilder.build()); 514 } 515 } 516 517 public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { 518 setUnknownFields( 519 UnknownFieldSet.newBuilder(getUnknownFields()) 520 .mergeFrom(unknownFields) 521 .build()); 522 return (BuilderType) this; 523 } 524 525 /** 526 * Construct an UninitializedMessageException reporting missing fields in 527 * the given message. 528 */ 529 protected static UninitializedMessageException 530 newUninitializedMessageException(Message message) { 531 return new UninitializedMessageException(findMissingFields(message)); 532 } 533 534 /** 535 * Populates {@code this.missingFields} with the full "path" of each 536 * missing required field in the given message. 537 */ 538 private static List<String> findMissingFields(final Message message) { 539 final List<String> results = new ArrayList<String>(); 540 findMissingFields(message, "", results); 541 return results; 542 } 543 544 /** Recursive helper implementing {@link #findMissingFields(Message)}. */ 545 private static void findMissingFields(final Message message, 546 final String prefix, 547 final List<String> results) { 548 for (final FieldDescriptor field : 549 message.getDescriptorForType().getFields()) { 550 if (field.isRequired() && !message.hasField(field)) { 551 results.add(prefix + field.getName()); 552 } 553 } 554 555 for (final Map.Entry<FieldDescriptor, Object> entry : 556 message.getAllFields().entrySet()) { 557 final FieldDescriptor field = entry.getKey(); 558 final Object value = entry.getValue(); 559 560 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 561 if (field.isRepeated()) { 562 int i = 0; 563 for (final Object element : (List) value) { 564 findMissingFields((Message) element, 565 subMessagePrefix(prefix, field, i++), 566 results); 567 } 568 } else { 569 if (message.hasField(field)) { 570 findMissingFields((Message) value, 571 subMessagePrefix(prefix, field, -1), 572 results); 573 } 574 } 575 } 576 } 577 } 578 579 private static String subMessagePrefix(final String prefix, 580 final FieldDescriptor field, 581 final int index) { 582 final StringBuilder result = new StringBuilder(prefix); 583 if (field.isExtension()) { 584 result.append('(') 585 .append(field.getFullName()) 586 .append(')'); 587 } else { 588 result.append(field.getName()); 589 } 590 if (index != -1) { 591 result.append('[') 592 .append(index) 593 .append(']'); 594 } 595 result.append('.'); 596 return result.toString(); 597 } 598 599 // =============================================================== 600 // The following definitions seem to be required in order to make javac 601 // not produce weird errors like: 602 // 603 // java/com/google/protobuf/DynamicMessage.java:203: types 604 // com.google.protobuf.AbstractMessage.Builder< 605 // com.google.protobuf.DynamicMessage.Builder> and 606 // com.google.protobuf.AbstractMessage.Builder< 607 // com.google.protobuf.DynamicMessage.Builder> are incompatible; both 608 // define mergeFrom(com.google.protobuf.ByteString), but with unrelated 609 // return types. 610 // 611 // Strangely, these lines are only needed if javac is invoked separately 612 // on AbstractMessage.java and AbstractMessageLite.java. If javac is 613 // invoked on both simultaneously, it works. (Or maybe the important 614 // point is whether or not DynamicMessage.java is compiled together with 615 // AbstractMessageLite.java -- not sure.) I suspect this is a compiler 616 // bug. 617 618 @Override 619 public BuilderType mergeFrom(final ByteString data) 620 throws InvalidProtocolBufferException { 621 return super.mergeFrom(data); 622 } 623 624 @Override 625 public BuilderType mergeFrom( 626 final ByteString data, 627 final ExtensionRegistryLite extensionRegistry) 628 throws InvalidProtocolBufferException { 629 return super.mergeFrom(data, extensionRegistry); 630 } 631 632 @Override 633 public BuilderType mergeFrom(final byte[] data) 634 throws InvalidProtocolBufferException { 635 return super.mergeFrom(data); 636 } 637 638 @Override 639 public BuilderType mergeFrom( 640 final byte[] data, final int off, final int len) 641 throws InvalidProtocolBufferException { 642 return super.mergeFrom(data, off, len); 643 } 644 645 @Override 646 public BuilderType mergeFrom( 647 final byte[] data, 648 final ExtensionRegistryLite extensionRegistry) 649 throws InvalidProtocolBufferException { 650 return super.mergeFrom(data, extensionRegistry); 651 } 652 653 @Override 654 public BuilderType mergeFrom( 655 final byte[] data, final int off, final int len, 656 final ExtensionRegistryLite extensionRegistry) 657 throws InvalidProtocolBufferException { 658 return super.mergeFrom(data, off, len, extensionRegistry); 659 } 660 661 @Override 662 public BuilderType mergeFrom(final InputStream input) 663 throws IOException { 664 return super.mergeFrom(input); 665 } 666 667 @Override 668 public BuilderType mergeFrom( 669 final InputStream input, 670 final ExtensionRegistryLite extensionRegistry) 671 throws IOException { 672 return super.mergeFrom(input, extensionRegistry); 673 } 674 675 @Override 676 public BuilderType mergeDelimitedFrom(final InputStream input) 677 throws IOException { 678 return super.mergeDelimitedFrom(input); 679 } 680 681 @Override 682 public BuilderType mergeDelimitedFrom( 683 final InputStream input, 684 final ExtensionRegistryLite extensionRegistry) 685 throws IOException { 686 return super.mergeDelimitedFrom(input, extensionRegistry); 687 } 688 689 } 690} 691