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.AbstractMessageLite.Builder.LimitedInputStream; 34 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.io.OutputStream; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.Collections; 41 import java.util.List; 42 import java.util.Map; 43 import java.util.TreeMap; 44 45 /** 46 * {@code UnknownFieldSet} is used to keep track of fields which were seen when 47 * parsing a protocol message but whose field numbers or types are unrecognized. 48 * This most frequently occurs when new fields are added to a message type 49 * and then messages containing those fields are read by old software that was 50 * compiled before the new types were added. 51 * 52 * <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every 53 * {@link Message.Builder} contains an {@link Builder}). 54 * 55 * <p>Most users will never need to use this class. 56 * 57 * @author kenton@google.com Kenton Varda 58 */ 59 public final class UnknownFieldSet implements MessageLite { UnknownFieldSet()60 private UnknownFieldSet() {} 61 62 /** Create a new {@link Builder}. */ newBuilder()63 public static Builder newBuilder() { 64 return Builder.create(); 65 } 66 67 /** 68 * Create a new {@link Builder} and initialize it to be a copy 69 * of {@code copyFrom}. 70 */ newBuilder(final UnknownFieldSet copyFrom)71 public static Builder newBuilder(final UnknownFieldSet copyFrom) { 72 return newBuilder().mergeFrom(copyFrom); 73 } 74 75 /** Get an empty {@code UnknownFieldSet}. */ getDefaultInstance()76 public static UnknownFieldSet getDefaultInstance() { 77 return defaultInstance; 78 } getDefaultInstanceForType()79 public UnknownFieldSet getDefaultInstanceForType() { 80 return defaultInstance; 81 } 82 private static final UnknownFieldSet defaultInstance = 83 new UnknownFieldSet(Collections.<Integer, Field>emptyMap()); 84 85 /** 86 * Construct an {@code UnknownFieldSet} around the given map. The map is 87 * expected to be immutable. 88 */ UnknownFieldSet(final Map<Integer, Field> fields)89 private UnknownFieldSet(final Map<Integer, Field> fields) { 90 this.fields = fields; 91 } 92 private Map<Integer, Field> fields; 93 94 95 @Override equals(final Object other)96 public boolean equals(final Object other) { 97 if (this == other) { 98 return true; 99 } 100 return (other instanceof UnknownFieldSet) && 101 fields.equals(((UnknownFieldSet) other).fields); 102 } 103 104 @Override hashCode()105 public int hashCode() { 106 return fields.hashCode(); 107 } 108 109 /** Get a map of fields in the set by number. */ asMap()110 public Map<Integer, Field> asMap() { 111 return fields; 112 } 113 114 /** Check if the given field number is present in the set. */ hasField(final int number)115 public boolean hasField(final int number) { 116 return fields.containsKey(number); 117 } 118 119 /** 120 * Get a field by number. Returns an empty field if not present. Never 121 * returns {@code null}. 122 */ getField(final int number)123 public Field getField(final int number) { 124 final Field result = fields.get(number); 125 return (result == null) ? Field.getDefaultInstance() : result; 126 } 127 128 /** Serializes the set and writes it to {@code output}. */ writeTo(final CodedOutputStream output)129 public void writeTo(final CodedOutputStream output) throws IOException { 130 for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { 131 entry.getValue().writeTo(entry.getKey(), output); 132 } 133 } 134 135 /** 136 * Converts the set to a string in protocol buffer text format. This is 137 * just a trivial wrapper around 138 * {@link TextFormat#printToString(UnknownFieldSet)}. 139 */ 140 @Override toString()141 public String toString() { 142 return TextFormat.printToString(this); 143 } 144 145 /** 146 * Serializes the message to a {@code ByteString} and returns it. This is 147 * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}. 148 */ toByteString()149 public ByteString toByteString() { 150 try { 151 final ByteString.CodedBuilder out = 152 ByteString.newCodedBuilder(getSerializedSize()); 153 writeTo(out.getCodedOutput()); 154 return out.build(); 155 } catch (final IOException e) { 156 throw new RuntimeException( 157 "Serializing to a ByteString threw an IOException (should " + 158 "never happen).", e); 159 } 160 } 161 162 /** 163 * Serializes the message to a {@code byte} array and returns it. This is 164 * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}. 165 */ toByteArray()166 public byte[] toByteArray() { 167 try { 168 final byte[] result = new byte[getSerializedSize()]; 169 final CodedOutputStream output = CodedOutputStream.newInstance(result); 170 writeTo(output); 171 output.checkNoSpaceLeft(); 172 return result; 173 } catch (final IOException e) { 174 throw new RuntimeException( 175 "Serializing to a byte array threw an IOException " + 176 "(should never happen).", e); 177 } 178 } 179 180 /** 181 * Serializes the message and writes it to {@code output}. This is just a 182 * trivial wrapper around {@link #writeTo(CodedOutputStream)}. 183 */ writeTo(final OutputStream output)184 public void writeTo(final OutputStream output) throws IOException { 185 final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); 186 writeTo(codedOutput); 187 codedOutput.flush(); 188 } 189 writeDelimitedTo(OutputStream output)190 public void writeDelimitedTo(OutputStream output) throws IOException { 191 final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); 192 codedOutput.writeRawVarint32(getSerializedSize()); 193 writeTo(codedOutput); 194 codedOutput.flush(); 195 } 196 197 /** Get the number of bytes required to encode this set. */ getSerializedSize()198 public int getSerializedSize() { 199 int result = 0; 200 for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { 201 result += entry.getValue().getSerializedSize(entry.getKey()); 202 } 203 return result; 204 } 205 206 /** 207 * Serializes the set and writes it to {@code output} using 208 * {@code MessageSet} wire format. 209 */ writeAsMessageSetTo(final CodedOutputStream output)210 public void writeAsMessageSetTo(final CodedOutputStream output) 211 throws IOException { 212 for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { 213 entry.getValue().writeAsMessageSetExtensionTo( 214 entry.getKey(), output); 215 } 216 } 217 218 /** 219 * Get the number of bytes required to encode this set using 220 * {@code MessageSet} wire format. 221 */ getSerializedSizeAsMessageSet()222 public int getSerializedSizeAsMessageSet() { 223 int result = 0; 224 for (final Map.Entry<Integer, Field> entry : fields.entrySet()) { 225 result += entry.getValue().getSerializedSizeAsMessageSetExtension( 226 entry.getKey()); 227 } 228 return result; 229 } 230 isInitialized()231 public boolean isInitialized() { 232 // UnknownFieldSets do not have required fields, so they are always 233 // initialized. 234 return true; 235 } 236 237 /** Parse an {@code UnknownFieldSet} from the given input stream. */ parseFrom(final CodedInputStream input)238 public static UnknownFieldSet parseFrom(final CodedInputStream input) 239 throws IOException { 240 return newBuilder().mergeFrom(input).build(); 241 } 242 243 /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */ parseFrom(final ByteString data)244 public static UnknownFieldSet parseFrom(final ByteString data) 245 throws InvalidProtocolBufferException { 246 return newBuilder().mergeFrom(data).build(); 247 } 248 249 /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */ parseFrom(final byte[] data)250 public static UnknownFieldSet parseFrom(final byte[] data) 251 throws InvalidProtocolBufferException { 252 return newBuilder().mergeFrom(data).build(); 253 } 254 255 /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */ parseFrom(final InputStream input)256 public static UnknownFieldSet parseFrom(final InputStream input) 257 throws IOException { 258 return newBuilder().mergeFrom(input).build(); 259 } 260 newBuilderForType()261 public Builder newBuilderForType() { 262 return newBuilder(); 263 } 264 toBuilder()265 public Builder toBuilder() { 266 return newBuilder().mergeFrom(this); 267 } 268 269 /** 270 * Builder for {@link UnknownFieldSet}s. 271 * 272 * <p>Note that this class maintains {@link Field.Builder}s for all fields 273 * in the set. Thus, adding one element to an existing {@link Field} does not 274 * require making a copy. This is important for efficient parsing of 275 * unknown repeated fields. However, it implies that {@link Field}s cannot 276 * be constructed independently, nor can two {@link UnknownFieldSet}s share 277 * the same {@code Field} object. 278 * 279 * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}. 280 */ 281 public static final class Builder implements MessageLite.Builder { 282 // This constructor should never be called directly (except from 'create'). Builder()283 private Builder() {} 284 285 private Map<Integer, Field> fields; 286 287 // Optimization: We keep around a builder for the last field that was 288 // modified so that we can efficiently add to it multiple times in a 289 // row (important when parsing an unknown repeated field). 290 private int lastFieldNumber; 291 private Field.Builder lastField; 292 create()293 private static Builder create() { 294 Builder builder = new Builder(); 295 builder.reinitialize(); 296 return builder; 297 } 298 299 /** 300 * Get a field builder for the given field number which includes any 301 * values that already exist. 302 */ getFieldBuilder(final int number)303 private Field.Builder getFieldBuilder(final int number) { 304 if (lastField != null) { 305 if (number == lastFieldNumber) { 306 return lastField; 307 } 308 // Note: addField() will reset lastField and lastFieldNumber. 309 addField(lastFieldNumber, lastField.build()); 310 } 311 if (number == 0) { 312 return null; 313 } else { 314 final Field existing = fields.get(number); 315 lastFieldNumber = number; 316 lastField = Field.newBuilder(); 317 if (existing != null) { 318 lastField.mergeFrom(existing); 319 } 320 return lastField; 321 } 322 } 323 324 /** 325 * Build the {@link UnknownFieldSet} and return it. 326 * 327 * <p>Once {@code build()} has been called, the {@code Builder} will no 328 * longer be usable. Calling any method after {@code build()} will result 329 * in undefined behavior and can cause a {@code NullPointerException} to be 330 * thrown. 331 */ build()332 public UnknownFieldSet build() { 333 getFieldBuilder(0); // Force lastField to be built. 334 final UnknownFieldSet result; 335 if (fields.isEmpty()) { 336 result = getDefaultInstance(); 337 } else { 338 result = new UnknownFieldSet(Collections.unmodifiableMap(fields)); 339 } 340 fields = null; 341 return result; 342 } 343 buildPartial()344 public UnknownFieldSet buildPartial() { 345 // No required fields, so this is the same as build(). 346 return build(); 347 } 348 349 @Override clone()350 public Builder clone() { 351 getFieldBuilder(0); // Force lastField to be built. 352 return UnknownFieldSet.newBuilder().mergeFrom( 353 new UnknownFieldSet(fields)); 354 } 355 getDefaultInstanceForType()356 public UnknownFieldSet getDefaultInstanceForType() { 357 return UnknownFieldSet.getDefaultInstance(); 358 } 359 reinitialize()360 private void reinitialize() { 361 fields = Collections.emptyMap(); 362 lastFieldNumber = 0; 363 lastField = null; 364 } 365 366 /** Reset the builder to an empty set. */ clear()367 public Builder clear() { 368 reinitialize(); 369 return this; 370 } 371 372 /** Clear fields from the set with a given field number. */ clearField(final int number)373 public Builder clearField(final int number) { 374 if (number == 0) { 375 throw new IllegalArgumentException("Zero is not a valid field number."); 376 } 377 if (lastField != null && lastFieldNumber == number) { 378 // Discard this. 379 lastField = null; 380 lastFieldNumber = 0; 381 } 382 if (fields.containsKey(number)) { 383 fields.remove(number); 384 } 385 return this; 386 } 387 388 /** 389 * Merge the fields from {@code other} into this set. If a field number 390 * exists in both sets, {@code other}'s values for that field will be 391 * appended to the values in this set. 392 */ mergeFrom(final UnknownFieldSet other)393 public Builder mergeFrom(final UnknownFieldSet other) { 394 if (other != getDefaultInstance()) { 395 for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) { 396 mergeField(entry.getKey(), entry.getValue()); 397 } 398 } 399 return this; 400 } 401 402 /** 403 * Add a field to the {@code UnknownFieldSet}. If a field with the same 404 * number already exists, the two are merged. 405 */ mergeField(final int number, final Field field)406 public Builder mergeField(final int number, final Field field) { 407 if (number == 0) { 408 throw new IllegalArgumentException("Zero is not a valid field number."); 409 } 410 if (hasField(number)) { 411 getFieldBuilder(number).mergeFrom(field); 412 } else { 413 // Optimization: We could call getFieldBuilder(number).mergeFrom(field) 414 // in this case, but that would create a copy of the Field object. 415 // We'd rather reuse the one passed to us, so call addField() instead. 416 addField(number, field); 417 } 418 return this; 419 } 420 421 /** 422 * Convenience method for merging a new field containing a single varint 423 * value. This is used in particular when an unknown enum value is 424 * encountered. 425 */ mergeVarintField(final int number, final int value)426 public Builder mergeVarintField(final int number, final int value) { 427 if (number == 0) { 428 throw new IllegalArgumentException("Zero is not a valid field number."); 429 } 430 getFieldBuilder(number).addVarint(value); 431 return this; 432 } 433 434 /** Check if the given field number is present in the set. */ hasField(final int number)435 public boolean hasField(final int number) { 436 if (number == 0) { 437 throw new IllegalArgumentException("Zero is not a valid field number."); 438 } 439 return number == lastFieldNumber || fields.containsKey(number); 440 } 441 442 /** 443 * Add a field to the {@code UnknownFieldSet}. If a field with the same 444 * number already exists, it is removed. 445 */ addField(final int number, final Field field)446 public Builder addField(final int number, final Field field) { 447 if (number == 0) { 448 throw new IllegalArgumentException("Zero is not a valid field number."); 449 } 450 if (lastField != null && lastFieldNumber == number) { 451 // Discard this. 452 lastField = null; 453 lastFieldNumber = 0; 454 } 455 if (fields.isEmpty()) { 456 fields = new TreeMap<Integer,Field>(); 457 } 458 fields.put(number, field); 459 return this; 460 } 461 462 /** 463 * Get all present {@code Field}s as an immutable {@code Map}. If more 464 * fields are added, the changes may or may not be reflected in this map. 465 */ asMap()466 public Map<Integer, Field> asMap() { 467 getFieldBuilder(0); // Force lastField to be built. 468 return Collections.unmodifiableMap(fields); 469 } 470 471 /** 472 * Parse an entire message from {@code input} and merge its fields into 473 * this set. 474 */ mergeFrom(final CodedInputStream input)475 public Builder mergeFrom(final CodedInputStream input) throws IOException { 476 while (true) { 477 final int tag = input.readTag(); 478 if (tag == 0 || !mergeFieldFrom(tag, input)) { 479 break; 480 } 481 } 482 return this; 483 } 484 485 /** 486 * Parse a single field from {@code input} and merge it into this set. 487 * @param tag The field's tag number, which was already parsed. 488 * @return {@code false} if the tag is an end group tag. 489 */ mergeFieldFrom(final int tag, final CodedInputStream input)490 public boolean mergeFieldFrom(final int tag, final CodedInputStream input) 491 throws IOException { 492 final int number = WireFormat.getTagFieldNumber(tag); 493 switch (WireFormat.getTagWireType(tag)) { 494 case WireFormat.WIRETYPE_VARINT: 495 getFieldBuilder(number).addVarint(input.readInt64()); 496 return true; 497 case WireFormat.WIRETYPE_FIXED64: 498 getFieldBuilder(number).addFixed64(input.readFixed64()); 499 return true; 500 case WireFormat.WIRETYPE_LENGTH_DELIMITED: 501 getFieldBuilder(number).addLengthDelimited(input.readBytes()); 502 return true; 503 case WireFormat.WIRETYPE_START_GROUP: 504 final Builder subBuilder = newBuilder(); 505 input.readGroup(number, subBuilder, 506 ExtensionRegistry.getEmptyRegistry()); 507 getFieldBuilder(number).addGroup(subBuilder.build()); 508 return true; 509 case WireFormat.WIRETYPE_END_GROUP: 510 return false; 511 case WireFormat.WIRETYPE_FIXED32: 512 getFieldBuilder(number).addFixed32(input.readFixed32()); 513 return true; 514 default: 515 throw InvalidProtocolBufferException.invalidWireType(); 516 } 517 } 518 519 /** 520 * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the 521 * set being built. This is just a small wrapper around 522 * {@link #mergeFrom(CodedInputStream)}. 523 */ mergeFrom(final ByteString data)524 public Builder mergeFrom(final ByteString data) 525 throws InvalidProtocolBufferException { 526 try { 527 final CodedInputStream input = data.newCodedInput(); 528 mergeFrom(input); 529 input.checkLastTagWas(0); 530 return this; 531 } catch (final InvalidProtocolBufferException e) { 532 throw e; 533 } catch (final IOException e) { 534 throw new RuntimeException( 535 "Reading from a ByteString threw an IOException (should " + 536 "never happen).", e); 537 } 538 } 539 540 /** 541 * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the 542 * set being built. This is just a small wrapper around 543 * {@link #mergeFrom(CodedInputStream)}. 544 */ mergeFrom(final byte[] data)545 public Builder mergeFrom(final byte[] data) 546 throws InvalidProtocolBufferException { 547 try { 548 final CodedInputStream input = CodedInputStream.newInstance(data); 549 mergeFrom(input); 550 input.checkLastTagWas(0); 551 return this; 552 } catch (final InvalidProtocolBufferException e) { 553 throw e; 554 } catch (final IOException e) { 555 throw new RuntimeException( 556 "Reading from a byte array threw an IOException (should " + 557 "never happen).", e); 558 } 559 } 560 561 /** 562 * Parse an {@code UnknownFieldSet} from {@code input} and merge it with the 563 * set being built. This is just a small wrapper around 564 * {@link #mergeFrom(CodedInputStream)}. 565 */ mergeFrom(final InputStream input)566 public Builder mergeFrom(final InputStream input) throws IOException { 567 final CodedInputStream codedInput = CodedInputStream.newInstance(input); 568 mergeFrom(codedInput); 569 codedInput.checkLastTagWas(0); 570 return this; 571 } 572 mergeDelimitedFrom(InputStream input)573 public boolean mergeDelimitedFrom(InputStream input) 574 throws IOException { 575 final int firstByte = input.read(); 576 if (firstByte == -1) { 577 return false; 578 } 579 final int size = CodedInputStream.readRawVarint32(firstByte, input); 580 final InputStream limitedInput = new LimitedInputStream(input, size); 581 mergeFrom(limitedInput); 582 return true; 583 } 584 mergeDelimitedFrom( InputStream input, ExtensionRegistryLite extensionRegistry)585 public boolean mergeDelimitedFrom( 586 InputStream input, 587 ExtensionRegistryLite extensionRegistry) throws IOException { 588 // UnknownFieldSet has no extensions. 589 return mergeDelimitedFrom(input); 590 } 591 mergeFrom( CodedInputStream input, ExtensionRegistryLite extensionRegistry)592 public Builder mergeFrom( 593 CodedInputStream input, 594 ExtensionRegistryLite extensionRegistry) throws IOException { 595 // UnknownFieldSet has no extensions. 596 return mergeFrom(input); 597 } 598 mergeFrom( ByteString data, ExtensionRegistryLite extensionRegistry)599 public Builder mergeFrom( 600 ByteString data, 601 ExtensionRegistryLite extensionRegistry) 602 throws InvalidProtocolBufferException { 603 // UnknownFieldSet has no extensions. 604 return mergeFrom(data); 605 } 606 mergeFrom(byte[] data, int off, int len)607 public Builder mergeFrom(byte[] data, int off, int len) 608 throws InvalidProtocolBufferException { 609 try { 610 final CodedInputStream input = 611 CodedInputStream.newInstance(data, off, len); 612 mergeFrom(input); 613 input.checkLastTagWas(0); 614 return this; 615 } catch (InvalidProtocolBufferException e) { 616 throw e; 617 } catch (IOException e) { 618 throw new RuntimeException( 619 "Reading from a byte array threw an IOException (should " + 620 "never happen).", e); 621 } 622 } 623 mergeFrom( byte[] data, ExtensionRegistryLite extensionRegistry)624 public Builder mergeFrom( 625 byte[] data, 626 ExtensionRegistryLite extensionRegistry) 627 throws InvalidProtocolBufferException { 628 // UnknownFieldSet has no extensions. 629 return mergeFrom(data); 630 } 631 mergeFrom( byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)632 public Builder mergeFrom( 633 byte[] data, int off, int len, 634 ExtensionRegistryLite extensionRegistry) 635 throws InvalidProtocolBufferException { 636 // UnknownFieldSet has no extensions. 637 return mergeFrom(data, off, len); 638 } 639 mergeFrom( InputStream input, ExtensionRegistryLite extensionRegistry)640 public Builder mergeFrom( 641 InputStream input, 642 ExtensionRegistryLite extensionRegistry) throws IOException { 643 // UnknownFieldSet has no extensions. 644 return mergeFrom(input); 645 } 646 isInitialized()647 public boolean isInitialized() { 648 // UnknownFieldSets do not have required fields, so they are always 649 // initialized. 650 return true; 651 } 652 } 653 654 /** 655 * Represents a single field in an {@code UnknownFieldSet}. 656 * 657 * <p>A {@code Field} consists of five lists of values. The lists correspond 658 * to the five "wire types" used in the protocol buffer binary format. 659 * The wire type of each field can be determined from the encoded form alone, 660 * without knowing the field's declared type. So, we are able to parse 661 * unknown values at least this far and separate them. Normally, only one 662 * of the five lists will contain any values, since it is impossible to 663 * define a valid message type that declares two different types for the 664 * same field number. However, the code is designed to allow for the case 665 * where the same unknown field number is encountered using multiple different 666 * wire types. 667 * 668 * <p>{@code Field} is an immutable class. To construct one, you must use a 669 * {@link Builder}. 670 * 671 * @see UnknownFieldSet 672 */ 673 public static final class Field { Field()674 private Field() {} 675 676 /** Construct a new {@link Builder}. */ newBuilder()677 public static Builder newBuilder() { 678 return Builder.create(); 679 } 680 681 /** 682 * Construct a new {@link Builder} and initialize it to a copy of 683 * {@code copyFrom}. 684 */ newBuilder(final Field copyFrom)685 public static Builder newBuilder(final Field copyFrom) { 686 return newBuilder().mergeFrom(copyFrom); 687 } 688 689 /** Get an empty {@code Field}. */ getDefaultInstance()690 public static Field getDefaultInstance() { 691 return fieldDefaultInstance; 692 } 693 private static final Field fieldDefaultInstance = newBuilder().build(); 694 695 /** Get the list of varint values for this field. */ getVarintList()696 public List<Long> getVarintList() { return varint; } 697 698 /** Get the list of fixed32 values for this field. */ getFixed32List()699 public List<Integer> getFixed32List() { return fixed32; } 700 701 /** Get the list of fixed64 values for this field. */ getFixed64List()702 public List<Long> getFixed64List() { return fixed64; } 703 704 /** Get the list of length-delimited values for this field. */ getLengthDelimitedList()705 public List<ByteString> getLengthDelimitedList() { return lengthDelimited; } 706 707 /** 708 * Get the list of embedded group values for this field. These are 709 * represented using {@link UnknownFieldSet}s rather than {@link Message}s 710 * since the group's type is presumably unknown. 711 */ getGroupList()712 public List<UnknownFieldSet> getGroupList() { return group; } 713 714 @Override equals(final Object other)715 public boolean equals(final Object other) { 716 if (this == other) { 717 return true; 718 } 719 if (!(other instanceof Field)) { 720 return false; 721 } 722 return Arrays.equals(getIdentityArray(), 723 ((Field) other).getIdentityArray()); 724 } 725 726 @Override hashCode()727 public int hashCode() { 728 return Arrays.hashCode(getIdentityArray()); 729 } 730 731 /** 732 * Returns the array of objects to be used to uniquely identify this 733 * {@link Field} instance. 734 */ getIdentityArray()735 private Object[] getIdentityArray() { 736 return new Object[] { 737 varint, 738 fixed32, 739 fixed64, 740 lengthDelimited, 741 group}; 742 } 743 744 /** 745 * Serializes the field, including field number, and writes it to 746 * {@code output}. 747 */ writeTo(final int fieldNumber, final CodedOutputStream output)748 public void writeTo(final int fieldNumber, final CodedOutputStream output) 749 throws IOException { 750 for (final long value : varint) { 751 output.writeUInt64(fieldNumber, value); 752 } 753 for (final int value : fixed32) { 754 output.writeFixed32(fieldNumber, value); 755 } 756 for (final long value : fixed64) { 757 output.writeFixed64(fieldNumber, value); 758 } 759 for (final ByteString value : lengthDelimited) { 760 output.writeBytes(fieldNumber, value); 761 } 762 for (final UnknownFieldSet value : group) { 763 output.writeGroup(fieldNumber, value); 764 } 765 } 766 767 /** 768 * Get the number of bytes required to encode this field, including field 769 * number. 770 */ getSerializedSize(final int fieldNumber)771 public int getSerializedSize(final int fieldNumber) { 772 int result = 0; 773 for (final long value : varint) { 774 result += CodedOutputStream.computeUInt64Size(fieldNumber, value); 775 } 776 for (final int value : fixed32) { 777 result += CodedOutputStream.computeFixed32Size(fieldNumber, value); 778 } 779 for (final long value : fixed64) { 780 result += CodedOutputStream.computeFixed64Size(fieldNumber, value); 781 } 782 for (final ByteString value : lengthDelimited) { 783 result += CodedOutputStream.computeBytesSize(fieldNumber, value); 784 } 785 for (final UnknownFieldSet value : group) { 786 result += CodedOutputStream.computeGroupSize(fieldNumber, value); 787 } 788 return result; 789 } 790 791 /** 792 * Serializes the field, including field number, and writes it to 793 * {@code output}, using {@code MessageSet} wire format. 794 */ writeAsMessageSetExtensionTo( final int fieldNumber, final CodedOutputStream output)795 public void writeAsMessageSetExtensionTo( 796 final int fieldNumber, 797 final CodedOutputStream output) 798 throws IOException { 799 for (final ByteString value : lengthDelimited) { 800 output.writeRawMessageSetExtension(fieldNumber, value); 801 } 802 } 803 804 /** 805 * Get the number of bytes required to encode this field, including field 806 * number, using {@code MessageSet} wire format. 807 */ getSerializedSizeAsMessageSetExtension(final int fieldNumber)808 public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) { 809 int result = 0; 810 for (final ByteString value : lengthDelimited) { 811 result += CodedOutputStream.computeRawMessageSetExtensionSize( 812 fieldNumber, value); 813 } 814 return result; 815 } 816 817 private List<Long> varint; 818 private List<Integer> fixed32; 819 private List<Long> fixed64; 820 private List<ByteString> lengthDelimited; 821 private List<UnknownFieldSet> group; 822 823 /** 824 * Used to build a {@link Field} within an {@link UnknownFieldSet}. 825 * 826 * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}. 827 */ 828 public static final class Builder { 829 // This constructor should never be called directly (except from 'create'). Builder()830 private Builder() {} 831 create()832 private static Builder create() { 833 Builder builder = new Builder(); 834 builder.result = new Field(); 835 return builder; 836 } 837 838 private Field result; 839 840 /** 841 * Build the field. After {@code build()} has been called, the 842 * {@code Builder} is no longer usable. Calling any other method will 843 * result in undefined behavior and can cause a 844 * {@code NullPointerException} to be thrown. 845 */ build()846 public Field build() { 847 if (result.varint == null) { 848 result.varint = Collections.emptyList(); 849 } else { 850 result.varint = Collections.unmodifiableList(result.varint); 851 } 852 if (result.fixed32 == null) { 853 result.fixed32 = Collections.emptyList(); 854 } else { 855 result.fixed32 = Collections.unmodifiableList(result.fixed32); 856 } 857 if (result.fixed64 == null) { 858 result.fixed64 = Collections.emptyList(); 859 } else { 860 result.fixed64 = Collections.unmodifiableList(result.fixed64); 861 } 862 if (result.lengthDelimited == null) { 863 result.lengthDelimited = Collections.emptyList(); 864 } else { 865 result.lengthDelimited = 866 Collections.unmodifiableList(result.lengthDelimited); 867 } 868 if (result.group == null) { 869 result.group = Collections.emptyList(); 870 } else { 871 result.group = Collections.unmodifiableList(result.group); 872 } 873 874 final Field returnMe = result; 875 result = null; 876 return returnMe; 877 } 878 879 /** Discard the field's contents. */ clear()880 public Builder clear() { 881 result = new Field(); 882 return this; 883 } 884 885 /** 886 * Merge the values in {@code other} into this field. For each list 887 * of values, {@code other}'s values are append to the ones in this 888 * field. 889 */ mergeFrom(final Field other)890 public Builder mergeFrom(final Field other) { 891 if (!other.varint.isEmpty()) { 892 if (result.varint == null) { 893 result.varint = new ArrayList<Long>(); 894 } 895 result.varint.addAll(other.varint); 896 } 897 if (!other.fixed32.isEmpty()) { 898 if (result.fixed32 == null) { 899 result.fixed32 = new ArrayList<Integer>(); 900 } 901 result.fixed32.addAll(other.fixed32); 902 } 903 if (!other.fixed64.isEmpty()) { 904 if (result.fixed64 == null) { 905 result.fixed64 = new ArrayList<Long>(); 906 } 907 result.fixed64.addAll(other.fixed64); 908 } 909 if (!other.lengthDelimited.isEmpty()) { 910 if (result.lengthDelimited == null) { 911 result.lengthDelimited = new ArrayList<ByteString>(); 912 } 913 result.lengthDelimited.addAll(other.lengthDelimited); 914 } 915 if (!other.group.isEmpty()) { 916 if (result.group == null) { 917 result.group = new ArrayList<UnknownFieldSet>(); 918 } 919 result.group.addAll(other.group); 920 } 921 return this; 922 } 923 924 /** Add a varint value. */ addVarint(final long value)925 public Builder addVarint(final long value) { 926 if (result.varint == null) { 927 result.varint = new ArrayList<Long>(); 928 } 929 result.varint.add(value); 930 return this; 931 } 932 933 /** Add a fixed32 value. */ addFixed32(final int value)934 public Builder addFixed32(final int value) { 935 if (result.fixed32 == null) { 936 result.fixed32 = new ArrayList<Integer>(); 937 } 938 result.fixed32.add(value); 939 return this; 940 } 941 942 /** Add a fixed64 value. */ addFixed64(final long value)943 public Builder addFixed64(final long value) { 944 if (result.fixed64 == null) { 945 result.fixed64 = new ArrayList<Long>(); 946 } 947 result.fixed64.add(value); 948 return this; 949 } 950 951 /** Add a length-delimited value. */ addLengthDelimited(final ByteString value)952 public Builder addLengthDelimited(final ByteString value) { 953 if (result.lengthDelimited == null) { 954 result.lengthDelimited = new ArrayList<ByteString>(); 955 } 956 result.lengthDelimited.add(value); 957 return this; 958 } 959 960 /** Add an embedded group. */ addGroup(final UnknownFieldSet value)961 public Builder addGroup(final UnknownFieldSet value) { 962 if (result.group == null) { 963 result.group = new ArrayList<UnknownFieldSet>(); 964 } 965 result.group.add(value); 966 return this; 967 } 968 } 969 } 970 971 /** 972 * Parser to implement MessageLite interface. 973 */ 974 public static final class Parser extends AbstractParser<UnknownFieldSet> { parsePartialFrom( CodedInputStream input, ExtensionRegistryLite extensionRegistry)975 public UnknownFieldSet parsePartialFrom( 976 CodedInputStream input, ExtensionRegistryLite extensionRegistry) 977 throws InvalidProtocolBufferException { 978 Builder builder = newBuilder(); 979 try { 980 builder.mergeFrom(input); 981 } catch (InvalidProtocolBufferException e) { 982 throw e.setUnfinishedMessage(builder.buildPartial()); 983 } catch (IOException e) { 984 throw new InvalidProtocolBufferException(e.getMessage()) 985 .setUnfinishedMessage(builder.buildPartial()); 986 } 987 return builder.buildPartial(); 988 } 989 } 990 991 private static final Parser PARSER = new Parser(); getParserForType()992 public final Parser getParserForType() { 993 return PARSER; 994 } 995 } 996