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 com.google.protobuf.Descriptors.EnumValueDescriptor; 34 import com.google.protobuf.Descriptors.FieldDescriptor; 35 import com.google.protobuf.Descriptors.OneofDescriptor; 36 import com.google.protobuf.Internal.EnumLite; 37 38 import java.io.IOException; 39 import java.io.InputStream; 40 import java.util.Arrays; 41 import java.util.Collections; 42 import java.util.HashMap; 43 import java.util.Iterator; 44 import java.util.List; 45 import java.util.Map; 46 47 /** 48 * A partial implementation of the {@link Message} interface which implements 49 * as many methods of that interface as possible in terms of other methods. 50 * 51 * @author kenton@google.com Kenton Varda 52 */ 53 public abstract class AbstractMessage 54 // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType. 55 extends AbstractMessageLite 56 implements Message { 57 58 @Override isInitialized()59 public boolean isInitialized() { 60 return MessageReflection.isInitialized(this); 61 } 62 63 /** 64 * Interface for the parent of a Builder that allows the builder to 65 * communicate invalidations back to the parent for use when using nested 66 * builders. 67 */ 68 protected interface BuilderParent { 69 70 /** 71 * A builder becomes dirty whenever a field is modified -- including fields 72 * in nested builders -- and becomes clean when build() is called. Thus, 73 * when a builder becomes dirty, all its parents become dirty as well, and 74 * when it becomes clean, all its children become clean. The dirtiness 75 * state is used to invalidate certain cached values. 76 * <br> 77 * To this end, a builder calls markDirty() on its parent whenever it 78 * transitions from clean to dirty. The parent must propagate this call to 79 * its own parent, unless it was already dirty, in which case the 80 * grandparent must necessarily already be dirty as well. The parent can 81 * only transition back to "clean" after calling build() on all children. 82 */ markDirty()83 void markDirty(); 84 } 85 86 /** Create a nested builder. */ newBuilderForType(BuilderParent parent)87 protected Message.Builder newBuilderForType(BuilderParent parent) { 88 throw new UnsupportedOperationException("Nested builder is not supported for this type."); 89 } 90 91 92 @Override findInitializationErrors()93 public List<String> findInitializationErrors() { 94 return MessageReflection.findMissingFields(this); 95 } 96 97 @Override getInitializationErrorString()98 public String getInitializationErrorString() { 99 return MessageReflection.delimitWithCommas(findInitializationErrors()); 100 } 101 102 /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ 103 @Override hasOneof(OneofDescriptor oneof)104 public boolean hasOneof(OneofDescriptor oneof) { 105 throw new UnsupportedOperationException("hasOneof() is not implemented."); 106 } 107 108 /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ 109 @Override getOneofFieldDescriptor(OneofDescriptor oneof)110 public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { 111 throw new UnsupportedOperationException( 112 "getOneofFieldDescriptor() is not implemented."); 113 } 114 115 @Override toString()116 public final String toString() { 117 return TextFormat.printToString(this); 118 } 119 120 @Override writeTo(final CodedOutputStream output)121 public void writeTo(final CodedOutputStream output) throws IOException { 122 MessageReflection.writeMessageTo(this, getAllFields(), output, false); 123 } 124 125 protected int memoizedSize = -1; 126 127 @Override getSerializedSize()128 public int getSerializedSize() { 129 int size = memoizedSize; 130 if (size != -1) { 131 return size; 132 } 133 134 memoizedSize = MessageReflection.getSerializedSize(this, getAllFields()); 135 return memoizedSize; 136 } 137 138 @Override equals(final Object other)139 public boolean equals(final Object other) { 140 if (other == this) { 141 return true; 142 } 143 if (!(other instanceof Message)) { 144 return false; 145 } 146 final Message otherMessage = (Message) other; 147 if (getDescriptorForType() != otherMessage.getDescriptorForType()) { 148 return false; 149 } 150 return compareFields(getAllFields(), otherMessage.getAllFields()) && 151 getUnknownFields().equals(otherMessage.getUnknownFields()); 152 } 153 154 @Override hashCode()155 public int hashCode() { 156 int hash = memoizedHashCode; 157 if (hash == 0) { 158 hash = 41; 159 hash = (19 * hash) + getDescriptorForType().hashCode(); 160 hash = hashFields(hash, getAllFields()); 161 hash = (29 * hash) + getUnknownFields().hashCode(); 162 memoizedHashCode = hash; 163 } 164 return hash; 165 } 166 toByteString(Object value)167 private static ByteString toByteString(Object value) { 168 if (value instanceof byte[]) { 169 return ByteString.copyFrom((byte[]) value); 170 } else { 171 return (ByteString) value; 172 } 173 } 174 175 /** 176 * Compares two bytes fields. The parameters must be either a byte array or a 177 * ByteString object. They can be of different type though. 178 */ compareBytes(Object a, Object b)179 private static boolean compareBytes(Object a, Object b) { 180 if (a instanceof byte[] && b instanceof byte[]) { 181 return Arrays.equals((byte[])a, (byte[])b); 182 } 183 return toByteString(a).equals(toByteString(b)); 184 } 185 186 /** 187 * Converts a list of MapEntry messages into a Map used for equals() and 188 * hashCode(). 189 */ 190 @SuppressWarnings({"rawtypes", "unchecked"}) convertMapEntryListToMap(List list)191 private static Map convertMapEntryListToMap(List list) { 192 if (list.isEmpty()) { 193 return Collections.emptyMap(); 194 } 195 Map result = new HashMap(); 196 Iterator iterator = list.iterator(); 197 Message entry = (Message) iterator.next(); 198 Descriptors.Descriptor descriptor = entry.getDescriptorForType(); 199 Descriptors.FieldDescriptor key = descriptor.findFieldByName("key"); 200 Descriptors.FieldDescriptor value = descriptor.findFieldByName("value"); 201 Object fieldValue = entry.getField(value); 202 if (fieldValue instanceof EnumValueDescriptor) { 203 fieldValue = ((EnumValueDescriptor) fieldValue).getNumber(); 204 } 205 result.put(entry.getField(key), fieldValue); 206 while (iterator.hasNext()) { 207 entry = (Message) iterator.next(); 208 fieldValue = entry.getField(value); 209 if (fieldValue instanceof EnumValueDescriptor) { 210 fieldValue = ((EnumValueDescriptor) fieldValue).getNumber(); 211 } 212 result.put(entry.getField(key), fieldValue); 213 } 214 return result; 215 } 216 217 /** 218 * Compares two map fields. The parameters must be a list of MapEntry 219 * messages. 220 */ 221 @SuppressWarnings({"rawtypes", "unchecked"}) compareMapField(Object a, Object b)222 private static boolean compareMapField(Object a, Object b) { 223 Map ma = convertMapEntryListToMap((List) a); 224 Map mb = convertMapEntryListToMap((List) b); 225 return MapFieldLite.equals(ma, mb); 226 } 227 228 /** 229 * Compares two set of fields. 230 * This method is used to implement {@link AbstractMessage#equals(Object)} 231 * and {@link AbstractMutableMessage#equals(Object)}. It takes special care 232 * of bytes fields because immutable messages and mutable messages use 233 * different Java type to reprensent a bytes field and this method should be 234 * able to compare immutable messages, mutable messages and also an immutable 235 * message to a mutable message. 236 */ compareFields(Map<FieldDescriptor, Object> a, Map<FieldDescriptor, Object> b)237 static boolean compareFields(Map<FieldDescriptor, Object> a, 238 Map<FieldDescriptor, Object> b) { 239 if (a.size() != b.size()) { 240 return false; 241 } 242 for (FieldDescriptor descriptor : a.keySet()) { 243 if (!b.containsKey(descriptor)) { 244 return false; 245 } 246 Object value1 = a.get(descriptor); 247 Object value2 = b.get(descriptor); 248 if (descriptor.getType() == FieldDescriptor.Type.BYTES) { 249 if (descriptor.isRepeated()) { 250 List list1 = (List) value1; 251 List list2 = (List) value2; 252 if (list1.size() != list2.size()) { 253 return false; 254 } 255 for (int i = 0; i < list1.size(); i++) { 256 if (!compareBytes(list1.get(i), list2.get(i))) { 257 return false; 258 } 259 } 260 } else { 261 // Compares a singular bytes field. 262 if (!compareBytes(value1, value2)) { 263 return false; 264 } 265 } 266 } else if (descriptor.isMapField()) { 267 if (!compareMapField(value1, value2)) { 268 return false; 269 } 270 } else { 271 // Compare non-bytes fields. 272 if (!value1.equals(value2)) { 273 return false; 274 } 275 } 276 } 277 return true; 278 } 279 280 /** 281 * Calculates the hash code of a map field. {@code value} must be a list of 282 * MapEntry messages. 283 */ 284 @SuppressWarnings("unchecked") hashMapField(Object value)285 private static int hashMapField(Object value) { 286 return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value)); 287 } 288 289 /** Get a hash code for given fields and values, using the given seed. */ 290 @SuppressWarnings("unchecked") hashFields(int hash, Map<FieldDescriptor, Object> map)291 protected static int hashFields(int hash, Map<FieldDescriptor, Object> map) { 292 for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) { 293 FieldDescriptor field = entry.getKey(); 294 Object value = entry.getValue(); 295 hash = (37 * hash) + field.getNumber(); 296 if (field.isMapField()) { 297 hash = (53 * hash) + hashMapField(value); 298 } else if (field.getType() != FieldDescriptor.Type.ENUM){ 299 hash = (53 * hash) + value.hashCode(); 300 } else if (field.isRepeated()) { 301 List<? extends EnumLite> list = (List<? extends EnumLite>) value; 302 hash = (53 * hash) + Internal.hashEnumList(list); 303 } else { 304 hash = (53 * hash) + Internal.hashEnum((EnumLite) value); 305 } 306 } 307 return hash; 308 } 309 310 /** 311 * Package private helper method for AbstractParser to create 312 * UninitializedMessageException with missing field information. 313 */ 314 @Override newUninitializedMessageException()315 UninitializedMessageException newUninitializedMessageException() { 316 return Builder.newUninitializedMessageException(this); 317 } 318 319 // ================================================================= 320 321 /** 322 * A partial implementation of the {@link Message.Builder} interface which 323 * implements as many methods of that interface as possible in terms of 324 * other methods. 325 */ 326 @SuppressWarnings("unchecked") 327 public static abstract class Builder<BuilderType extends Builder<BuilderType>> 328 extends AbstractMessageLite.Builder 329 implements Message.Builder { 330 // The compiler produces an error if this is not declared explicitly. 331 @Override clone()332 public abstract BuilderType clone(); 333 334 /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ 335 @Override hasOneof(OneofDescriptor oneof)336 public boolean hasOneof(OneofDescriptor oneof) { 337 throw new UnsupportedOperationException("hasOneof() is not implemented."); 338 } 339 340 /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ 341 @Override getOneofFieldDescriptor(OneofDescriptor oneof)342 public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { 343 throw new UnsupportedOperationException( 344 "getOneofFieldDescriptor() is not implemented."); 345 } 346 347 /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ 348 @Override clearOneof(OneofDescriptor oneof)349 public BuilderType clearOneof(OneofDescriptor oneof) { 350 throw new UnsupportedOperationException("clearOneof() is not implemented."); 351 } 352 353 @Override clear()354 public BuilderType clear() { 355 for (final Map.Entry<FieldDescriptor, Object> entry : 356 getAllFields().entrySet()) { 357 clearField(entry.getKey()); 358 } 359 return (BuilderType) this; 360 } 361 362 @Override findInitializationErrors()363 public List<String> findInitializationErrors() { 364 return MessageReflection.findMissingFields(this); 365 } 366 367 @Override getInitializationErrorString()368 public String getInitializationErrorString() { 369 return MessageReflection.delimitWithCommas(findInitializationErrors()); 370 } 371 372 @Override internalMergeFrom(AbstractMessageLite other)373 protected BuilderType internalMergeFrom(AbstractMessageLite other) { 374 return mergeFrom((Message) other); 375 } 376 377 @Override mergeFrom(final Message other)378 public BuilderType mergeFrom(final Message other) { 379 if (other.getDescriptorForType() != getDescriptorForType()) { 380 throw new IllegalArgumentException( 381 "mergeFrom(Message) can only merge messages of the same type."); 382 } 383 384 // Note: We don't attempt to verify that other's fields have valid 385 // types. Doing so would be a losing battle. We'd have to verify 386 // all sub-messages as well, and we'd have to make copies of all of 387 // them to insure that they don't change after verification (since 388 // the Message interface itself cannot enforce immutability of 389 // implementations). 390 // TODO(kenton): Provide a function somewhere called makeDeepCopy() 391 // which allows people to make secure deep copies of messages. 392 393 for (final Map.Entry<FieldDescriptor, Object> entry : 394 other.getAllFields().entrySet()) { 395 final FieldDescriptor field = entry.getKey(); 396 if (field.isRepeated()) { 397 for (final Object element : (List)entry.getValue()) { 398 addRepeatedField(field, element); 399 } 400 } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { 401 final Message existingValue = (Message)getField(field); 402 if (existingValue == existingValue.getDefaultInstanceForType()) { 403 setField(field, entry.getValue()); 404 } else { 405 setField(field, 406 existingValue.newBuilderForType() 407 .mergeFrom(existingValue) 408 .mergeFrom((Message)entry.getValue()) 409 .build()); 410 } 411 } else { 412 setField(field, entry.getValue()); 413 } 414 } 415 416 mergeUnknownFields(other.getUnknownFields()); 417 418 return (BuilderType) this; 419 } 420 421 @Override mergeFrom(final CodedInputStream input)422 public BuilderType mergeFrom(final CodedInputStream input) 423 throws IOException { 424 return mergeFrom(input, ExtensionRegistry.getEmptyRegistry()); 425 } 426 427 @Override mergeFrom( final CodedInputStream input, final ExtensionRegistryLite extensionRegistry)428 public BuilderType mergeFrom( 429 final CodedInputStream input, 430 final ExtensionRegistryLite extensionRegistry) 431 throws IOException { 432 final UnknownFieldSet.Builder unknownFields = 433 UnknownFieldSet.newBuilder(getUnknownFields()); 434 while (true) { 435 final int tag = input.readTag(); 436 if (tag == 0) { 437 break; 438 } 439 440 MessageReflection.BuilderAdapter builderAdapter = 441 new MessageReflection.BuilderAdapter(this); 442 if (!MessageReflection.mergeFieldFrom(input, unknownFields, 443 extensionRegistry, 444 getDescriptorForType(), 445 builderAdapter, 446 tag)) { 447 // end group tag 448 break; 449 } 450 } 451 setUnknownFields(unknownFields.build()); 452 return (BuilderType) this; 453 } 454 455 @Override mergeUnknownFields(final UnknownFieldSet unknownFields)456 public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { 457 setUnknownFields( 458 UnknownFieldSet.newBuilder(getUnknownFields()) 459 .mergeFrom(unknownFields) 460 .build()); 461 return (BuilderType) this; 462 } 463 464 @Override getFieldBuilder(final FieldDescriptor field)465 public Message.Builder getFieldBuilder(final FieldDescriptor field) { 466 throw new UnsupportedOperationException( 467 "getFieldBuilder() called on an unsupported message type."); 468 } 469 470 @Override getRepeatedFieldBuilder(final FieldDescriptor field, int index)471 public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) { 472 throw new UnsupportedOperationException( 473 "getRepeatedFieldBuilder() called on an unsupported message type."); 474 } 475 476 @Override toString()477 public String toString() { 478 return TextFormat.printToString(this); 479 } 480 481 /** 482 * Construct an UninitializedMessageException reporting missing fields in 483 * the given message. 484 */ 485 protected static UninitializedMessageException newUninitializedMessageException(Message message)486 newUninitializedMessageException(Message message) { 487 return new UninitializedMessageException( 488 MessageReflection.findMissingFields(message)); 489 } 490 491 /** 492 * Used to support nested builders and called to mark this builder as clean. 493 * Clean builders will propagate the {@link BuilderParent#markDirty()} event 494 * to their parent builders, while dirty builders will not, as their parents 495 * should be dirty already. 496 * 497 * NOTE: Implementations that don't support nested builders don't need to 498 * override this method. 499 */ markClean()500 void markClean() { 501 throw new IllegalStateException("Should be overridden by subclasses."); 502 } 503 504 /** 505 * Used to support nested builders and called when this nested builder is 506 * no longer used by its parent builder and should release the reference 507 * to its parent builder. 508 * 509 * NOTE: Implementations that don't support nested builders don't need to 510 * override this method. 511 */ dispose()512 void dispose() { 513 throw new IllegalStateException("Should be overridden by subclasses."); 514 } 515 516 // =============================================================== 517 // The following definitions seem to be required in order to make javac 518 // not produce weird errors like: 519 // 520 // java/com/google/protobuf/DynamicMessage.java:203: types 521 // com.google.protobuf.AbstractMessage.Builder< 522 // com.google.protobuf.DynamicMessage.Builder> and 523 // com.google.protobuf.AbstractMessage.Builder< 524 // com.google.protobuf.DynamicMessage.Builder> are incompatible; both 525 // define mergeFrom(com.google.protobuf.ByteString), but with unrelated 526 // return types. 527 // 528 // Strangely, these lines are only needed if javac is invoked separately 529 // on AbstractMessage.java and AbstractMessageLite.java. If javac is 530 // invoked on both simultaneously, it works. (Or maybe the important 531 // point is whether or not DynamicMessage.java is compiled together with 532 // AbstractMessageLite.java -- not sure.) I suspect this is a compiler 533 // bug. 534 535 @Override mergeFrom(final ByteString data)536 public BuilderType mergeFrom(final ByteString data) 537 throws InvalidProtocolBufferException { 538 return (BuilderType) super.mergeFrom(data); 539 } 540 541 @Override mergeFrom( final ByteString data, final ExtensionRegistryLite extensionRegistry)542 public BuilderType mergeFrom( 543 final ByteString data, 544 final ExtensionRegistryLite extensionRegistry) 545 throws InvalidProtocolBufferException { 546 return (BuilderType) super.mergeFrom(data, extensionRegistry); 547 } 548 549 @Override mergeFrom(final byte[] data)550 public BuilderType mergeFrom(final byte[] data) 551 throws InvalidProtocolBufferException { 552 return (BuilderType) super.mergeFrom(data); 553 } 554 555 @Override mergeFrom( final byte[] data, final int off, final int len)556 public BuilderType mergeFrom( 557 final byte[] data, final int off, final int len) 558 throws InvalidProtocolBufferException { 559 return (BuilderType) super.mergeFrom(data, off, len); 560 } 561 562 @Override mergeFrom( final byte[] data, final ExtensionRegistryLite extensionRegistry)563 public BuilderType mergeFrom( 564 final byte[] data, 565 final ExtensionRegistryLite extensionRegistry) 566 throws InvalidProtocolBufferException { 567 return (BuilderType) super.mergeFrom(data, extensionRegistry); 568 } 569 570 @Override mergeFrom( final byte[] data, final int off, final int len, final ExtensionRegistryLite extensionRegistry)571 public BuilderType mergeFrom( 572 final byte[] data, final int off, final int len, 573 final ExtensionRegistryLite extensionRegistry) 574 throws InvalidProtocolBufferException { 575 return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry); 576 } 577 578 @Override mergeFrom(final InputStream input)579 public BuilderType mergeFrom(final InputStream input) 580 throws IOException { 581 return (BuilderType) super.mergeFrom(input); 582 } 583 584 @Override mergeFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry)585 public BuilderType mergeFrom( 586 final InputStream input, 587 final ExtensionRegistryLite extensionRegistry) 588 throws IOException { 589 return (BuilderType) super.mergeFrom(input, extensionRegistry); 590 } 591 592 @Override mergeDelimitedFrom(final InputStream input)593 public boolean mergeDelimitedFrom(final InputStream input) 594 throws IOException { 595 return super.mergeDelimitedFrom(input); 596 } 597 598 @Override mergeDelimitedFrom( final InputStream input, final ExtensionRegistryLite extensionRegistry)599 public boolean mergeDelimitedFrom( 600 final InputStream input, 601 final ExtensionRegistryLite extensionRegistry) 602 throws IOException { 603 return super.mergeDelimitedFrom(input, extensionRegistry); 604 } 605 } 606 607 /** 608 * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1 609 * generated code. 610 */ 611 @Deprecated hashLong(long n)612 protected static int hashLong(long n) { 613 return (int) (n ^ (n >>> 32)); 614 } 615 // 616 /** 617 * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1 618 * generated code. 619 */ 620 @Deprecated hashBoolean(boolean b)621 protected static int hashBoolean(boolean b) { 622 return b ? 1231 : 1237; 623 } 624 // 625 /** 626 * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1 627 * generated code. 628 */ 629 @Deprecated hashEnum(EnumLite e)630 protected static int hashEnum(EnumLite e) { 631 return e.getNumber(); 632 } 633 // 634 /** 635 * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1 636 * generated code. 637 */ 638 @Deprecated hashEnumList(List<? extends EnumLite> list)639 protected static int hashEnumList(List<? extends EnumLite> list) { 640 int hash = 1; 641 for (EnumLite e : list) { 642 hash = 31 * hash + hashEnum(e); 643 } 644 return hash; 645 } 646 } 647