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