67
66
MessageLite.Builder to, MessageLite from);
70
private Map<FieldDescriptorType, Object> fields;
69
private final SmallSortedMap<FieldDescriptorType, Object> fields;
70
private boolean isImmutable;
72
72
/** Construct a new FieldSet. */
73
73
private FieldSet() {
74
// Use a TreeMap because fields need to be in canonical order when
76
// TODO(kenton): Maybe use some sort of sparse array instead? It would
77
// even make sense to store the first 16 or so tags in a flat array
78
// to make DynamicMessage faster.
79
fields = new TreeMap<FieldDescriptorType, Object>();
74
this.fields = SmallSortedMap.newFieldMap(16);
105
101
/** Make this FieldSet immutable from this point forward. */
106
102
@SuppressWarnings("unchecked")
107
103
public void makeImmutable() {
108
for (final Map.Entry<FieldDescriptorType, Object> entry:
110
if (entry.getKey().isRepeated()) {
111
final List value = (List)entry.getValue();
112
fields.put(entry.getKey(), Collections.unmodifiableList(value));
115
fields = Collections.unmodifiableMap(fields);
107
fields.makeImmutable();
112
* Retuns whether the FieldSet is immutable. This is true if it is the
113
* {@link #emptySet} or if {@link #makeImmutable} were called.
115
* @return whether the FieldSet is immutable.
117
public boolean isImmutable() {
122
* Clones the FieldSet. The returned FieldSet will be mutable even if the
123
* original FieldSet was immutable.
125
* @return the newly cloned FieldSet
128
public FieldSet<FieldDescriptorType> clone() {
129
// We can't just call fields.clone because List objects in the map
130
// should not be shared.
131
FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
132
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
133
Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
134
FieldDescriptorType descriptor = entry.getKey();
135
clone.setField(descriptor, entry.getValue());
137
for (Map.Entry<FieldDescriptorType, Object> entry :
138
fields.getOverflowEntries()) {
139
FieldDescriptorType descriptor = entry.getKey();
140
clone.setField(descriptor, entry.getValue());
118
145
// =================================================================
126
153
* Get a simple map containing all the fields.
128
155
public Map<FieldDescriptorType, Object> getAllFields() {
129
return Collections.unmodifiableMap(fields);
156
return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
133
* Get an iterator to the field map. This iterator should not be leaked
134
* out of the protobuf library as it is not protected from mutation.
160
* Get an iterator to the field map. This iterator should not be leaked out
161
* of the protobuf library as it is not protected from mutation when
162
* fields is not immutable.
136
164
public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
137
165
return fields.entrySet().iterator();
336
364
* aren't actually present in the set, it is up to the caller to check
337
365
* that all required fields are present.
339
@SuppressWarnings("unchecked")
340
367
public boolean isInitialized() {
341
for (final Map.Entry<FieldDescriptorType, Object> entry:
343
final FieldDescriptorType descriptor = entry.getKey();
344
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
345
if (descriptor.isRepeated()) {
346
for (final MessageLite element:
347
(List<MessageLite>) entry.getValue()) {
348
if (!element.isInitialized()) {
353
if (!((MessageLite) entry.getValue()).isInitialized()) {
368
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
369
if (!isInitialized(fields.getArrayEntryAt(i))) {
373
for (final Map.Entry<FieldDescriptorType, Object> entry :
374
fields.getOverflowEntries()) {
375
if (!isInitialized(entry)) {
382
@SuppressWarnings("unchecked")
383
private boolean isInitialized(
384
final Map.Entry<FieldDescriptorType, Object> entry) {
385
final FieldDescriptorType descriptor = entry.getKey();
386
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
387
if (descriptor.isRepeated()) {
388
for (final MessageLite element:
389
(List<MessageLite>) entry.getValue()) {
390
if (!element.isInitialized()) {
395
if (!((MessageLite) entry.getValue()).isInitialized()) {
379
419
* Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
381
@SuppressWarnings("unchecked")
382
421
public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
383
for (final Map.Entry<FieldDescriptorType, Object> entry:
384
other.fields.entrySet()) {
385
final FieldDescriptorType descriptor = entry.getKey();
386
final Object otherValue = entry.getValue();
388
if (descriptor.isRepeated()) {
389
Object value = fields.get(descriptor);
391
// Our list is empty, but we still need to make a defensive copy of
392
// the other list since we don't know if the other FieldSet is still
394
fields.put(descriptor, new ArrayList((List) otherValue));
396
// Concatenate the lists.
397
((List) value).addAll((List) otherValue);
399
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
400
Object value = fields.get(descriptor);
402
fields.put(descriptor, otherValue);
404
// Merge the messages.
405
fields.put(descriptor,
406
descriptor.internalMergeFrom(
422
for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
423
mergeFromField(other.fields.getArrayEntryAt(i));
425
for (final Map.Entry<FieldDescriptorType, Object> entry :
426
other.fields.getOverflowEntries()) {
427
mergeFromField(entry);
431
@SuppressWarnings("unchecked")
432
private void mergeFromField(
433
final Map.Entry<FieldDescriptorType, Object> entry) {
434
final FieldDescriptorType descriptor = entry.getKey();
435
final Object otherValue = entry.getValue();
437
if (descriptor.isRepeated()) {
438
Object value = fields.get(descriptor);
440
// Our list is empty, but we still need to make a defensive copy of
441
// the other list since we don't know if the other FieldSet is still
443
fields.put(descriptor, new ArrayList((List) otherValue));
445
// Concatenate the lists.
446
((List) value).addAll((List) otherValue);
448
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
449
Object value = fields.get(descriptor);
451
fields.put(descriptor, otherValue);
453
// Merge the messages.
456
descriptor.internalMergeFrom(
407
457
((MessageLite) value).toBuilder(), (MessageLite) otherValue)
412
fields.put(descriptor, otherValue);
462
fields.put(descriptor, otherValue);
468
517
/** See {@link Message#writeTo(CodedOutputStream)}. */
469
518
public void writeTo(final CodedOutputStream output)
470
519
throws IOException {
471
for (final Map.Entry<FieldDescriptorType, Object> entry:
520
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
521
final Map.Entry<FieldDescriptorType, Object> entry =
522
fields.getArrayEntryAt(i);
523
writeField(entry.getKey(), entry.getValue(), output);
525
for (final Map.Entry<FieldDescriptorType, Object> entry :
526
fields.getOverflowEntries()) {
473
527
writeField(entry.getKey(), entry.getValue(), output);
480
534
public void writeMessageSetTo(final CodedOutputStream output)
481
535
throws IOException {
482
for (final Map.Entry<FieldDescriptorType, Object> entry:
484
final FieldDescriptorType descriptor = entry.getKey();
485
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
486
!descriptor.isRepeated() && !descriptor.isPacked()) {
487
output.writeMessageSetExtension(entry.getKey().getNumber(),
488
(MessageLite) entry.getValue());
490
writeField(descriptor, entry.getValue(), output);
536
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
537
writeMessageSetTo(fields.getArrayEntryAt(i), output);
539
for (final Map.Entry<FieldDescriptorType, Object> entry :
540
fields.getOverflowEntries()) {
541
writeMessageSetTo(entry, output);
545
private void writeMessageSetTo(
546
final Map.Entry<FieldDescriptorType, Object> entry,
547
final CodedOutputStream output) throws IOException {
548
final FieldDescriptorType descriptor = entry.getKey();
549
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
550
!descriptor.isRepeated() && !descriptor.isPacked()) {
551
output.writeMessageSetExtension(entry.getKey().getNumber(),
552
(MessageLite) entry.getValue());
554
writeField(descriptor, entry.getValue(), output);
564
627
WireFormat.FieldType type = descriptor.getLiteType();
565
628
int number = descriptor.getNumber();
566
629
if (descriptor.isRepeated()) {
567
final List valueList = (List)value;
630
final List<?> valueList = (List<?>)value;
568
631
if (descriptor.isPacked()) {
569
632
output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
570
633
// Compute the total data size so the length can be written.
594
657
public int getSerializedSize() {
596
for (final Map.Entry<FieldDescriptorType, Object> entry:
659
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
660
final Map.Entry<FieldDescriptorType, Object> entry =
661
fields.getArrayEntryAt(i);
662
size += computeFieldSize(entry.getKey(), entry.getValue());
664
for (final Map.Entry<FieldDescriptorType, Object> entry :
665
fields.getOverflowEntries()) {
598
666
size += computeFieldSize(entry.getKey(), entry.getValue());
606
674
public int getMessageSetSerializedSize() {
608
for (final Map.Entry<FieldDescriptorType, Object> entry:
610
final FieldDescriptorType descriptor = entry.getKey();
611
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
612
!descriptor.isRepeated() && !descriptor.isPacked()) {
613
size += CodedOutputStream.computeMessageSetExtensionSize(
614
entry.getKey().getNumber(), (MessageLite) entry.getValue());
616
size += computeFieldSize(descriptor, entry.getValue());
676
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
677
size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
679
for (final Map.Entry<FieldDescriptorType, Object> entry :
680
fields.getOverflowEntries()) {
681
size += getMessageSetSerializedSize(entry);
686
private int getMessageSetSerializedSize(
687
final Map.Entry<FieldDescriptorType, Object> entry) {
688
final FieldDescriptorType descriptor = entry.getKey();
689
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
690
!descriptor.isRepeated() && !descriptor.isPacked()) {
691
return CodedOutputStream.computeMessageSetExtensionSize(
692
entry.getKey().getNumber(), (MessageLite) entry.getValue());
694
return computeFieldSize(descriptor, entry.getValue());
623
699
* Compute the number of bytes that would be needed to encode a
624
700
* single tag/value pair of arbitrary type.