• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.google.protobuf.Internal.checkNotNull;
34 import static com.google.protobuf.WireFormat.WIRETYPE_LENGTH_DELIMITED;
35 
36 import java.io.IOException;
37 import java.util.Arrays;
38 import java.util.List;
39 import java.util.Map;
40 
41 /** An adapter between the {@link Writer} interface and {@link CodedOutputStream}. */
42 @ExperimentalApi
43 final class CodedOutputStreamWriter implements Writer {
44   private final CodedOutputStream output;
45 
forCodedOutput(CodedOutputStream output)46   public static CodedOutputStreamWriter forCodedOutput(CodedOutputStream output) {
47     if (output.wrapper != null) {
48       return output.wrapper;
49     }
50     return new CodedOutputStreamWriter(output);
51   }
52 
CodedOutputStreamWriter(CodedOutputStream output)53   private CodedOutputStreamWriter(CodedOutputStream output) {
54     this.output = checkNotNull(output, "output");
55     this.output.wrapper = this;
56   }
57 
58   @Override
fieldOrder()59   public FieldOrder fieldOrder() {
60     return FieldOrder.ASCENDING;
61   }
62 
getTotalBytesWritten()63   public int getTotalBytesWritten() {
64     return output.getTotalBytesWritten();
65   }
66 
67   @Override
writeSFixed32(int fieldNumber, int value)68   public void writeSFixed32(int fieldNumber, int value) throws IOException {
69     output.writeSFixed32(fieldNumber, value);
70   }
71 
72   @Override
writeInt64(int fieldNumber, long value)73   public void writeInt64(int fieldNumber, long value) throws IOException {
74     output.writeInt64(fieldNumber, value);
75   }
76 
77   @Override
writeSFixed64(int fieldNumber, long value)78   public void writeSFixed64(int fieldNumber, long value) throws IOException {
79     output.writeSFixed64(fieldNumber, value);
80   }
81 
82   @Override
writeFloat(int fieldNumber, float value)83   public void writeFloat(int fieldNumber, float value) throws IOException {
84     output.writeFloat(fieldNumber, value);
85   }
86 
87   @Override
writeDouble(int fieldNumber, double value)88   public void writeDouble(int fieldNumber, double value) throws IOException {
89     output.writeDouble(fieldNumber, value);
90   }
91 
92   @Override
writeEnum(int fieldNumber, int value)93   public void writeEnum(int fieldNumber, int value) throws IOException {
94     output.writeEnum(fieldNumber, value);
95   }
96 
97   @Override
writeUInt64(int fieldNumber, long value)98   public void writeUInt64(int fieldNumber, long value) throws IOException {
99     output.writeUInt64(fieldNumber, value);
100   }
101 
102   @Override
writeInt32(int fieldNumber, int value)103   public void writeInt32(int fieldNumber, int value) throws IOException {
104     output.writeInt32(fieldNumber, value);
105   }
106 
107   @Override
writeFixed64(int fieldNumber, long value)108   public void writeFixed64(int fieldNumber, long value) throws IOException {
109     output.writeFixed64(fieldNumber, value);
110   }
111 
112   @Override
writeFixed32(int fieldNumber, int value)113   public void writeFixed32(int fieldNumber, int value) throws IOException {
114     output.writeFixed32(fieldNumber, value);
115   }
116 
117   @Override
writeBool(int fieldNumber, boolean value)118   public void writeBool(int fieldNumber, boolean value) throws IOException {
119     output.writeBool(fieldNumber, value);
120   }
121 
122   @Override
writeString(int fieldNumber, String value)123   public void writeString(int fieldNumber, String value) throws IOException {
124     output.writeString(fieldNumber, value);
125   }
126 
127   @Override
writeBytes(int fieldNumber, ByteString value)128   public void writeBytes(int fieldNumber, ByteString value) throws IOException {
129     output.writeBytes(fieldNumber, value);
130   }
131 
132   @Override
writeUInt32(int fieldNumber, int value)133   public void writeUInt32(int fieldNumber, int value) throws IOException {
134     output.writeUInt32(fieldNumber, value);
135   }
136 
137   @Override
writeSInt32(int fieldNumber, int value)138   public void writeSInt32(int fieldNumber, int value) throws IOException {
139     output.writeSInt32(fieldNumber, value);
140   }
141 
142   @Override
writeSInt64(int fieldNumber, long value)143   public void writeSInt64(int fieldNumber, long value) throws IOException {
144     output.writeSInt64(fieldNumber, value);
145   }
146 
147   @Override
writeMessage(int fieldNumber, Object value)148   public void writeMessage(int fieldNumber, Object value) throws IOException {
149     output.writeMessage(fieldNumber, (MessageLite) value);
150   }
151 
152   @Override
writeMessage(int fieldNumber, Object value, Schema schema)153   public void writeMessage(int fieldNumber, Object value, Schema schema) throws IOException {
154     output.writeMessage(fieldNumber, (MessageLite) value, schema);
155   }
156 
157   @Override
writeGroup(int fieldNumber, Object value)158   public void writeGroup(int fieldNumber, Object value) throws IOException {
159     output.writeGroup(fieldNumber, (MessageLite) value);
160   }
161 
162   @Override
writeGroup(int fieldNumber, Object value, Schema schema)163   public void writeGroup(int fieldNumber, Object value, Schema schema) throws IOException {
164     output.writeGroup(fieldNumber, (MessageLite) value, schema);
165   }
166 
167   @Override
writeStartGroup(int fieldNumber)168   public void writeStartGroup(int fieldNumber) throws IOException {
169     output.writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
170   }
171 
172   @Override
writeEndGroup(int fieldNumber)173   public void writeEndGroup(int fieldNumber) throws IOException {
174     output.writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
175   }
176 
177   @Override
writeMessageSetItem(int fieldNumber, Object value)178   public final void writeMessageSetItem(int fieldNumber, Object value) throws IOException {
179     if (value instanceof ByteString) {
180       output.writeRawMessageSetExtension(fieldNumber, (ByteString) value);
181     } else {
182       output.writeMessageSetExtension(fieldNumber, (MessageLite) value);
183     }
184   }
185 
186   @Override
writeInt32List(int fieldNumber, List<Integer> value, boolean packed)187   public void writeInt32List(int fieldNumber, List<Integer> value, boolean packed)
188       throws IOException {
189     if (packed) {
190       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
191 
192       // Compute and write the length of the data.
193       int dataSize = 0;
194       for (int i = 0; i < value.size(); ++i) {
195         dataSize += CodedOutputStream.computeInt32SizeNoTag(value.get(i));
196       }
197       output.writeUInt32NoTag(dataSize);
198 
199       // Write the data itself, without any tags.
200       for (int i = 0; i < value.size(); ++i) {
201         output.writeInt32NoTag(value.get(i));
202       }
203     } else {
204       for (int i = 0; i < value.size(); ++i) {
205         output.writeInt32(fieldNumber, value.get(i));
206       }
207     }
208   }
209 
210   @Override
writeFixed32List(int fieldNumber, List<Integer> value, boolean packed)211   public void writeFixed32List(int fieldNumber, List<Integer> value, boolean packed)
212       throws IOException {
213     if (packed) {
214       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
215 
216       // Compute and write the length of the data.
217       int dataSize = 0;
218       for (int i = 0; i < value.size(); ++i) {
219         dataSize += CodedOutputStream.computeFixed32SizeNoTag(value.get(i));
220       }
221       output.writeUInt32NoTag(dataSize);
222 
223       // Write the data itself, without any tags.
224       for (int i = 0; i < value.size(); ++i) {
225         output.writeFixed32NoTag(value.get(i));
226       }
227     } else {
228       for (int i = 0; i < value.size(); ++i) {
229         output.writeFixed32(fieldNumber, value.get(i));
230       }
231     }
232   }
233 
234   @Override
writeInt64List(int fieldNumber, List<Long> value, boolean packed)235   public void writeInt64List(int fieldNumber, List<Long> value, boolean packed) throws IOException {
236     if (packed) {
237       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
238 
239       // Compute and write the length of the data.
240       int dataSize = 0;
241       for (int i = 0; i < value.size(); ++i) {
242         dataSize += CodedOutputStream.computeInt64SizeNoTag(value.get(i));
243       }
244       output.writeUInt32NoTag(dataSize);
245 
246       // Write the data itself, without any tags.
247       for (int i = 0; i < value.size(); ++i) {
248         output.writeInt64NoTag(value.get(i));
249       }
250     } else {
251       for (int i = 0; i < value.size(); ++i) {
252         output.writeInt64(fieldNumber, value.get(i));
253       }
254     }
255   }
256 
257   @Override
writeUInt64List(int fieldNumber, List<Long> value, boolean packed)258   public void writeUInt64List(int fieldNumber, List<Long> value, boolean packed)
259       throws IOException {
260     if (packed) {
261       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
262 
263       // Compute and write the length of the data.
264       int dataSize = 0;
265       for (int i = 0; i < value.size(); ++i) {
266         dataSize += CodedOutputStream.computeUInt64SizeNoTag(value.get(i));
267       }
268       output.writeUInt32NoTag(dataSize);
269 
270       // Write the data itself, without any tags.
271       for (int i = 0; i < value.size(); ++i) {
272         output.writeUInt64NoTag(value.get(i));
273       }
274     } else {
275       for (int i = 0; i < value.size(); ++i) {
276         output.writeUInt64(fieldNumber, value.get(i));
277       }
278     }
279   }
280 
281   @Override
writeFixed64List(int fieldNumber, List<Long> value, boolean packed)282   public void writeFixed64List(int fieldNumber, List<Long> value, boolean packed)
283       throws IOException {
284     if (packed) {
285       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
286 
287       // Compute and write the length of the data.
288       int dataSize = 0;
289       for (int i = 0; i < value.size(); ++i) {
290         dataSize += CodedOutputStream.computeFixed64SizeNoTag(value.get(i));
291       }
292       output.writeUInt32NoTag(dataSize);
293 
294       // Write the data itself, without any tags.
295       for (int i = 0; i < value.size(); ++i) {
296         output.writeFixed64NoTag(value.get(i));
297       }
298     } else {
299       for (int i = 0; i < value.size(); ++i) {
300         output.writeFixed64(fieldNumber, value.get(i));
301       }
302     }
303   }
304 
305   @Override
writeFloatList(int fieldNumber, List<Float> value, boolean packed)306   public void writeFloatList(int fieldNumber, List<Float> value, boolean packed)
307       throws IOException {
308     if (packed) {
309       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
310 
311       // Compute and write the length of the data.
312       int dataSize = 0;
313       for (int i = 0; i < value.size(); ++i) {
314         dataSize += CodedOutputStream.computeFloatSizeNoTag(value.get(i));
315       }
316       output.writeUInt32NoTag(dataSize);
317 
318       // Write the data itself, without any tags.
319       for (int i = 0; i < value.size(); ++i) {
320         output.writeFloatNoTag(value.get(i));
321       }
322     } else {
323       for (int i = 0; i < value.size(); ++i) {
324         output.writeFloat(fieldNumber, value.get(i));
325       }
326     }
327   }
328 
329   @Override
writeDoubleList(int fieldNumber, List<Double> value, boolean packed)330   public void writeDoubleList(int fieldNumber, List<Double> value, boolean packed)
331       throws IOException {
332     if (packed) {
333       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
334 
335       // Compute and write the length of the data.
336       int dataSize = 0;
337       for (int i = 0; i < value.size(); ++i) {
338         dataSize += CodedOutputStream.computeDoubleSizeNoTag(value.get(i));
339       }
340       output.writeUInt32NoTag(dataSize);
341 
342       // Write the data itself, without any tags.
343       for (int i = 0; i < value.size(); ++i) {
344         output.writeDoubleNoTag(value.get(i));
345       }
346     } else {
347       for (int i = 0; i < value.size(); ++i) {
348         output.writeDouble(fieldNumber, value.get(i));
349       }
350     }
351   }
352 
353   @Override
writeEnumList(int fieldNumber, List<Integer> value, boolean packed)354   public void writeEnumList(int fieldNumber, List<Integer> value, boolean packed)
355       throws IOException {
356     if (packed) {
357       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
358 
359       // Compute and write the length of the data.
360       int dataSize = 0;
361       for (int i = 0; i < value.size(); ++i) {
362         dataSize += CodedOutputStream.computeEnumSizeNoTag(value.get(i));
363       }
364       output.writeUInt32NoTag(dataSize);
365 
366       // Write the data itself, without any tags.
367       for (int i = 0; i < value.size(); ++i) {
368         output.writeEnumNoTag(value.get(i));
369       }
370     } else {
371       for (int i = 0; i < value.size(); ++i) {
372         output.writeEnum(fieldNumber, value.get(i));
373       }
374     }
375   }
376 
377   @Override
writeBoolList(int fieldNumber, List<Boolean> value, boolean packed)378   public void writeBoolList(int fieldNumber, List<Boolean> value, boolean packed)
379       throws IOException {
380     if (packed) {
381       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
382 
383       // Compute and write the length of the data.
384       int dataSize = 0;
385       for (int i = 0; i < value.size(); ++i) {
386         dataSize += CodedOutputStream.computeBoolSizeNoTag(value.get(i));
387       }
388       output.writeUInt32NoTag(dataSize);
389 
390       // Write the data itself, without any tags.
391       for (int i = 0; i < value.size(); ++i) {
392         output.writeBoolNoTag(value.get(i));
393       }
394     } else {
395       for (int i = 0; i < value.size(); ++i) {
396         output.writeBool(fieldNumber, value.get(i));
397       }
398     }
399   }
400 
401   @Override
writeStringList(int fieldNumber, List<String> value)402   public void writeStringList(int fieldNumber, List<String> value) throws IOException {
403     if (value instanceof LazyStringList) {
404       final LazyStringList lazyList = (LazyStringList) value;
405       for (int i = 0; i < value.size(); ++i) {
406         writeLazyString(fieldNumber, lazyList.getRaw(i));
407       }
408     } else {
409       for (int i = 0; i < value.size(); ++i) {
410         output.writeString(fieldNumber, value.get(i));
411       }
412     }
413   }
414 
writeLazyString(int fieldNumber, Object value)415   private void writeLazyString(int fieldNumber, Object value) throws IOException {
416     if (value instanceof String) {
417       output.writeString(fieldNumber, (String) value);
418     } else {
419       output.writeBytes(fieldNumber, (ByteString) value);
420     }
421   }
422 
423   @Override
writeBytesList(int fieldNumber, List<ByteString> value)424   public void writeBytesList(int fieldNumber, List<ByteString> value) throws IOException {
425     for (int i = 0; i < value.size(); ++i) {
426       output.writeBytes(fieldNumber, value.get(i));
427     }
428   }
429 
430   @Override
writeUInt32List(int fieldNumber, List<Integer> value, boolean packed)431   public void writeUInt32List(int fieldNumber, List<Integer> value, boolean packed)
432       throws IOException {
433     if (packed) {
434       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
435 
436       // Compute and write the length of the data.
437       int dataSize = 0;
438       for (int i = 0; i < value.size(); ++i) {
439         dataSize += CodedOutputStream.computeUInt32SizeNoTag(value.get(i));
440       }
441       output.writeUInt32NoTag(dataSize);
442 
443       // Write the data itself, without any tags.
444       for (int i = 0; i < value.size(); ++i) {
445         output.writeUInt32NoTag(value.get(i));
446       }
447     } else {
448       for (int i = 0; i < value.size(); ++i) {
449         output.writeUInt32(fieldNumber, value.get(i));
450       }
451     }
452   }
453 
454   @Override
writeSFixed32List(int fieldNumber, List<Integer> value, boolean packed)455   public void writeSFixed32List(int fieldNumber, List<Integer> value, boolean packed)
456       throws IOException {
457     if (packed) {
458       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
459 
460       // Compute and write the length of the data.
461       int dataSize = 0;
462       for (int i = 0; i < value.size(); ++i) {
463         dataSize += CodedOutputStream.computeSFixed32SizeNoTag(value.get(i));
464       }
465       output.writeUInt32NoTag(dataSize);
466 
467       // Write the data itself, without any tags.
468       for (int i = 0; i < value.size(); ++i) {
469         output.writeSFixed32NoTag(value.get(i));
470       }
471     } else {
472       for (int i = 0; i < value.size(); ++i) {
473         output.writeSFixed32(fieldNumber, value.get(i));
474       }
475     }
476   }
477 
478   @Override
writeSFixed64List(int fieldNumber, List<Long> value, boolean packed)479   public void writeSFixed64List(int fieldNumber, List<Long> value, boolean packed)
480       throws IOException {
481     if (packed) {
482       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
483 
484       // Compute and write the length of the data.
485       int dataSize = 0;
486       for (int i = 0; i < value.size(); ++i) {
487         dataSize += CodedOutputStream.computeSFixed64SizeNoTag(value.get(i));
488       }
489       output.writeUInt32NoTag(dataSize);
490 
491       // Write the data itself, without any tags.
492       for (int i = 0; i < value.size(); ++i) {
493         output.writeSFixed64NoTag(value.get(i));
494       }
495     } else {
496       for (int i = 0; i < value.size(); ++i) {
497         output.writeSFixed64(fieldNumber, value.get(i));
498       }
499     }
500   }
501 
502   @Override
writeSInt32List(int fieldNumber, List<Integer> value, boolean packed)503   public void writeSInt32List(int fieldNumber, List<Integer> value, boolean packed)
504       throws IOException {
505     if (packed) {
506       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
507 
508       // Compute and write the length of the data.
509       int dataSize = 0;
510       for (int i = 0; i < value.size(); ++i) {
511         dataSize += CodedOutputStream.computeSInt32SizeNoTag(value.get(i));
512       }
513       output.writeUInt32NoTag(dataSize);
514 
515       // Write the data itself, without any tags.
516       for (int i = 0; i < value.size(); ++i) {
517         output.writeSInt32NoTag(value.get(i));
518       }
519     } else {
520       for (int i = 0; i < value.size(); ++i) {
521         output.writeSInt32(fieldNumber, value.get(i));
522       }
523     }
524   }
525 
526   @Override
writeSInt64List(int fieldNumber, List<Long> value, boolean packed)527   public void writeSInt64List(int fieldNumber, List<Long> value, boolean packed)
528       throws IOException {
529     if (packed) {
530       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
531 
532       // Compute and write the length of the data.
533       int dataSize = 0;
534       for (int i = 0; i < value.size(); ++i) {
535         dataSize += CodedOutputStream.computeSInt64SizeNoTag(value.get(i));
536       }
537       output.writeUInt32NoTag(dataSize);
538 
539       // Write the data itself, without any tags.
540       for (int i = 0; i < value.size(); ++i) {
541         output.writeSInt64NoTag(value.get(i));
542       }
543     } else {
544       for (int i = 0; i < value.size(); ++i) {
545         output.writeSInt64(fieldNumber, value.get(i));
546       }
547     }
548   }
549 
550   @Override
writeMessageList(int fieldNumber, List<?> value)551   public void writeMessageList(int fieldNumber, List<?> value) throws IOException {
552     for (int i = 0; i < value.size(); ++i) {
553       writeMessage(fieldNumber, value.get(i));
554     }
555   }
556 
557   @Override
writeMessageList(int fieldNumber, List<?> value, Schema schema)558   public void writeMessageList(int fieldNumber, List<?> value, Schema schema) throws IOException {
559     for (int i = 0; i < value.size(); ++i) {
560       writeMessage(fieldNumber, value.get(i), schema);
561     }
562   }
563 
564   @Override
writeGroupList(int fieldNumber, List<?> value)565   public void writeGroupList(int fieldNumber, List<?> value) throws IOException {
566     for (int i = 0; i < value.size(); ++i) {
567       writeGroup(fieldNumber, value.get(i));
568     }
569   }
570 
571   @Override
writeGroupList(int fieldNumber, List<?> value, Schema schema)572   public void writeGroupList(int fieldNumber, List<?> value, Schema schema) throws IOException {
573     for (int i = 0; i < value.size(); ++i) {
574       writeGroup(fieldNumber, value.get(i), schema);
575     }
576   }
577 
578   @Override
writeMap(int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map)579   public <K, V> void writeMap(int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map)
580       throws IOException {
581     if (output.isSerializationDeterministic()) {
582       writeDeterministicMap(fieldNumber, metadata, map);
583       return;
584     }
585     for (Map.Entry<K, V> entry : map.entrySet()) {
586       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
587       output.writeUInt32NoTag(
588           MapEntryLite.computeSerializedSize(metadata, entry.getKey(), entry.getValue()));
589       MapEntryLite.writeTo(output, metadata, entry.getKey(), entry.getValue());
590     }
591   }
592 
593   @SuppressWarnings("unchecked")
writeDeterministicMap( int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map)594   private <K, V> void writeDeterministicMap(
595       int fieldNumber, MapEntryLite.Metadata<K, V> metadata, Map<K, V> map) throws IOException {
596     switch (metadata.keyType) {
597       case BOOL:
598         V value;
599         if ((value = map.get(Boolean.FALSE)) != null) {
600           writeDeterministicBooleanMapEntry(
601               fieldNumber, /* key= */ false, value, (MapEntryLite.Metadata<Boolean, V>) metadata);
602         }
603         if ((value = map.get(Boolean.TRUE)) != null) {
604           writeDeterministicBooleanMapEntry(
605               fieldNumber, /* key= */ true, value, (MapEntryLite.Metadata<Boolean, V>) metadata);
606         }
607         break;
608       case FIXED32:
609       case INT32:
610       case SFIXED32:
611       case SINT32:
612       case UINT32:
613         writeDeterministicIntegerMap(
614             fieldNumber, (MapEntryLite.Metadata<Integer, V>) metadata, (Map<Integer, V>) map);
615         break;
616       case FIXED64:
617       case INT64:
618       case SFIXED64:
619       case SINT64:
620       case UINT64:
621         writeDeterministicLongMap(
622             fieldNumber, (MapEntryLite.Metadata<Long, V>) metadata, (Map<Long, V>) map);
623         break;
624       case STRING:
625         writeDeterministicStringMap(
626             fieldNumber, (MapEntryLite.Metadata<String, V>) metadata, (Map<String, V>) map);
627         break;
628       default:
629         throw new IllegalArgumentException("does not support key type: " + metadata.keyType);
630     }
631   }
632 
writeDeterministicBooleanMapEntry( int fieldNumber, boolean key, V value, MapEntryLite.Metadata<Boolean, V> metadata)633   private <V> void writeDeterministicBooleanMapEntry(
634       int fieldNumber, boolean key, V value, MapEntryLite.Metadata<Boolean, V> metadata)
635       throws IOException {
636     output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
637     output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
638     MapEntryLite.writeTo(output, metadata, key, value);
639   }
640 
writeDeterministicIntegerMap( int fieldNumber, MapEntryLite.Metadata<Integer, V> metadata, Map<Integer, V> map)641   private <V> void writeDeterministicIntegerMap(
642       int fieldNumber, MapEntryLite.Metadata<Integer, V> metadata, Map<Integer, V> map)
643       throws IOException {
644     int[] keys = new int[map.size()];
645     int index = 0;
646     for (int k : map.keySet()) {
647       keys[index++] = k;
648     }
649     Arrays.sort(keys);
650     for (int key : keys) {
651       V value = map.get(key);
652       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
653       output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
654       MapEntryLite.writeTo(output, metadata, key, value);
655     }
656   }
657 
writeDeterministicLongMap( int fieldNumber, MapEntryLite.Metadata<Long, V> metadata, Map<Long, V> map)658   private <V> void writeDeterministicLongMap(
659       int fieldNumber, MapEntryLite.Metadata<Long, V> metadata, Map<Long, V> map)
660       throws IOException {
661     long[] keys = new long[map.size()];
662     int index = 0;
663     for (long k : map.keySet()) {
664       keys[index++] = k;
665     }
666     Arrays.sort(keys);
667     for (long key : keys) {
668       V value = map.get(key);
669       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
670       output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
671       MapEntryLite.writeTo(output, metadata, key, value);
672     }
673   }
674 
writeDeterministicStringMap( int fieldNumber, MapEntryLite.Metadata<String, V> metadata, Map<String, V> map)675   private <V> void writeDeterministicStringMap(
676       int fieldNumber, MapEntryLite.Metadata<String, V> metadata, Map<String, V> map)
677       throws IOException {
678     String[] keys = new String[map.size()];
679     int index = 0;
680     for (String k : map.keySet()) {
681       keys[index++] = k;
682     }
683     Arrays.sort(keys);
684     for (String key : keys) {
685       V value = map.get(key);
686       output.writeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
687       output.writeUInt32NoTag(MapEntryLite.computeSerializedSize(metadata, key, value));
688       MapEntryLite.writeTo(output, metadata, key, value);
689     }
690   }
691 }
692